
/* "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_xtract.text" */


/* Change these for testing */



#include "global.h"


#define WOL_XTRACT_G
#include "wol_xtract.h"


Static boolean do_output;
Static FILE *ntk_out;


Static long renorm(long a)
{
  /* undo the *2+1 transform */
  return ((a - 1) / 2);
}


void xtract_init(void)
{
  /* Call me only once!! */
  m_init_pen(0);
  ext_init_mem();
  in_extract = false;
  xtr_display_nodes = false;   /* do not display nodes by default */
}


Static void add_to_list_2(node **boxes, node *element)
{
  /* creates a list in DECREASING sorted order */
  node *tmp_head, *prev_head;
  long area;
  long layerno;

  /*writeln ('adding box on layer: ', element^.layer);*/
  layerno = element->layer;
  if (boxes[layerno - min_layer] == NULL) {
    boxes[layerno - min_layer] = element;
    return;
  }
  tmp_head = boxes[layerno - min_layer];
  prev_head = boxes[layerno - min_layer];
  area = (element->ur.x - element->ll.x) * (element->ur.y - element->ll.y);
  while (tmp_head != NULL &&
	 (tmp_head->ur.x - tmp_head->ll.x) * (tmp_head->ur.y - tmp_head->ll.y) >
	 area) {
    prev_head = tmp_head;
    tmp_head = tmp_head->next;
  }
  if (tmp_head == boxes[layerno - min_layer]) {
    element->next = boxes[layerno - min_layer];
    boxes[layerno - min_layer] = element;
  } else {
    element->next = tmp_head;
    prev_head->next = element;
  }
}


#define clip_size       40   /* lambda */


/* Local variables for flatten: */
struct LOC_flatten {
  long number_of_boxes;
  long clipleft, clipright, cliptop, clipbot;
  box_array boxes;
  FILE *outfile;
} ;


/*$if false$
   PROCEDURE flush_boxes (boxes : box_array);
   var i : shortint;
       tmp : node_ptr;
   begin
     {for i := min_layer to max_layer do  }
     i := layer_well;
     while i <> 9999 do
       begin
           if boxes[i] <> nil then
             begin
                writeln (outfile, layers[i].cif_name, ';');
                tmp := boxes[i];
                while tmp <> nil do
                   begin
                     with tmp^ do
                        writeln (outfile, 'B ',
                            abs((ur.x - ll.x)*2):0,' ',abs((ur.y - ll.y)*2):0,' ',
                               (ur.x + ll.x):0,' ', (ur.y + ll.y):0, ' ;');
                     tmp := tmp^.next;
                   end;
              end;
          case i of
             layer_well:   i := layer_sel;
             layer_sel:    i := layer_metal2;
             layer_metal2: i := layer_metal;
             layer_metal:  i := layer_via;
             layer_via:    i := layer_diff;
             layer_diff:   i := layer_poly;
             layer_poly:   i := layer_cuta;
             layer_cuta:   i := layer_cutp;
             layer_cutp:   i := layer_glass;
             layer_glass:  i := layer_poly2;               {*}
             layer_poly2:  i := layer_cut2;                {*}
             layer_cut2:   i := 9999; { bogus exit flag }  {*}
           end; {case}
       end;
   end;
$end$*/

Local void flush_boxes(node **boxes, struct LOC_flatten *LINK)
{
  long i;
  node *tmp;

  for (i = min_layer; i <= max_layer; i++) {
    if (i != bb && boxes[i - min_layer] != NULL) {
      fprintf(LINK->outfile, "%s;\n", layers[i - min_layer].cif_name);
      tmp = boxes[i - min_layer];
      while (tmp != NULL) {
	fprintf(LINK->outfile, "B %ld %ld %ld %ld ;\n",
		labs((tmp->ur.x - tmp->ll.x) * 2),
		labs((tmp->ur.y - tmp->ll.y) * 2), tmp->ur.x + tmp->ll.x,
		tmp->ur.y + tmp->ll.y);
	tmp = tmp->next;
      }
    }
  }
}

Local long min(long a, long b)
{
  if (a > b)
    return b;
  else
    return a;
}

Local long max(long a, long b)
{
  if (a < b)
    return b;
  else
    return a;
}

Local void flatten_wire(node *tp, struct LOC_flatten *LINK)
{
  long tmp;
  node *newnode;

  tr_4(tp->ll.x, tp->ll.y, tp->ur.x, tp->ur.y);

  if (tr_bx < tr_ax) {
    tmp = tr_bx;
    tr_bx = tr_ax;
    tr_ax = tmp;
  }
  if (tr_by < tr_ay) {
    tmp = tr_by;
    tr_by = tr_ay;
    tr_ay = tmp;
  }
  /* now clip box, if necessary */
  if (tr_ax >= LINK->clipright || tr_bx <= LINK->clipleft ||
      tr_ay >= LINK->cliptop || tr_by <= LINK->clipbot)
    return;
  /* trivial reject */
  tr_ax = max(tr_ax, LINK->clipleft);
  tr_bx = min(tr_bx, LINK->clipright);
  tr_ay = max(tr_ay, LINK->clipbot);
  tr_by = min(tr_by, LINK->cliptop);
  newnode = get_a_node();
  *newnode = *tp;
  newnode->ll.x = tr_ax;
  newnode->ll.y = tr_ay;
  newnode->ur.x = tr_bx;
  newnode->ur.y = tr_by;
  newnode->child = NULL;
  newnode->next = NULL;
  /*writeln ('adding box to list');*/
  add_to_list_2(LINK->boxes, newnode);
  LINK->number_of_boxes++;
}

Local void flatten_geom_2(node *t_p, struct LOC_flatten *LINK)
{
  node *WITH;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in FLATTEN_GEOM", false);
    goto _L1;
  }

  while (t_p != NULL) {
    WITH = t_p;
    if (t_p->layer != bb)   /*t_p^.*/
      flatten_wire(t_p, LINK);

    /*$if false$  { don't know what we should do with ports }
           ports := {t_p^.}portlist;
           if (ports <> NIL) and display_ports then
             begin
               while ports <> NIL do
                 begin
                    a := transform_point (ports^.p1);    { XFORM }
                    b := transform_point (ports^.p2);
                    line_style(0);
                    m_move(a.x, a.y);
                    m_color (BLACK);
                    m_draw(b.x, b.y);
                    m_move(a.x, a.y);

                    if redisp_last_layer<>ports^.layerno then
                       begin
                          redisp_last_layer:=ports^.layerno;
                          set_layer(redisp_last_layer);
                       end;
                    line_style(2);
                    m_draw(b.x, b.y);
                    line_style(0);
                    ports := ports^.next;
                 end;
              end;
         $end$*/

    if (WITH->child != NULL)   /*t_p^.*/
      flatten_geom_2(WITH->child, LINK);
    t_p = WITH->next;   /*t_p^.*/
  }
_L1: ;
}

Local void flatten_geom(node *t_p, struct LOC_flatten *LINK)
{
  flatten_geom_2(t_p, LINK);
}

/* Local variables for flatten_routing: */
struct LOC_flatten_routing {
  struct LOC_flatten *LINK;
} ;

Local long min_(long a, long b)
{
  if (a > b)
    return b;
  else
    return a;
}

Local long max_(long a, long b)
{
  if (a < b)
    return b;
  else
    return a;
}

Local void flatten_routing_box(long l, long x1, long y1, long x2, long y2,
			       struct LOC_flatten_routing *LINK)
{
  long tmp;
  node *newnode;

  tr_4(x1, y1, x2, y2);
  if (tr_bx < tr_ax) {
    tmp = tr_bx;
    tr_bx = tr_ax;
    tr_ax = tmp;
  }
  if (tr_by < tr_ay) {
    tmp = tr_by;
    tr_by = tr_ay;
    tr_ay = tmp;
  }
  /* now clip box, if necessary */
  if (tr_ax >= LINK->LINK->clipright || tr_bx <= LINK->LINK->clipleft ||
      tr_ay >= LINK->LINK->cliptop || tr_by <= LINK->LINK->clipbot)
    return;
  /* trivial reject */
  tr_ax = max_(tr_ax, LINK->LINK->clipleft);
  tr_bx = min_(tr_bx, LINK->LINK->clipright);
  tr_ay = max_(tr_ay, LINK->LINK->clipbot);
  tr_by = min_(tr_by, LINK->LINK->cliptop);
  newnode = get_a_node();
  newnode->layer = l;
  newnode->ll.x = tr_ax;
  newnode->ll.y = tr_ay;
  newnode->ur.x = tr_bx;
  newnode->ur.y = tr_by;
  newnode->child = NULL;
  newnode->next = NULL;
  /*writeln ('adding box to list');*/
  add_to_list_2(LINK->LINK->boxes, newnode);
  LINK->LINK->number_of_boxes++;
}

Local void flatten_routing(routing *pt, struct LOC_flatten *LINK)
{
  struct LOC_flatten_routing V;
  routing *to_pt;
  long w;
  routing *WITH;

  V.LINK = LINK;
  while (pt != NULL) {
    to_pt = pt;
    while (to_pt != NULL) {
      WITH = to_pt;
      w = WITH->width / 2;   /*to_pt^.*/
      if (WITH->pt1.x == WITH->pt2.x) {   /* vertical */
	if (WITH->pt1.y > WITH->pt2.y)
	  flatten_routing_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y + w,
			      WITH->pt1.x + WITH->width - w, WITH->pt2.y - w,
			      &V);
	else
	  flatten_routing_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y - w,
			      WITH->pt1.x + WITH->width - w, WITH->pt2.y + w,
			      &V);
      } else if (WITH->pt1.y == WITH->pt2.y) {
	if (WITH->pt1.x > WITH->pt2.x)
	  flatten_routing_box(WITH->layer, WITH->pt1.x + w, WITH->pt1.y - w,
			      WITH->pt2.x - w, WITH->pt1.y + WITH->width - w,
			      &V);
	else
	  flatten_routing_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y - w,
			      WITH->pt2.x + w, WITH->pt1.y + WITH->width - w,
			      &V);
      } else
	printf("Can't do non-manhattan routing @ (%ld,%ld)\n",
	       WITH->pt1.x, WITH->pt1.y);
      to_pt = to_pt->to_point;
    }
    pt = pt->next;   /* horizontal */
  }

  /* horizontal */
}


Local void flatten_comp_2(c_cell *root, struct LOC_flatten *LINK)
{
  /* stacks up a transformation matrix */
  point tp2;
  tr_matrix old_matrix;
  long tmp;



  old_matrix = tr_ctm;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in SHOW_COMP", false);
    return;
  }
  TRY(try1);
    while (root != NULL) {
      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;

      /* trivial clip */
      tr_4(0, 0, tp2.x, tp2.y);
      if (tr_bx < tr_ax) {
	tmp = tr_bx;
	tr_bx = tr_ax;
	tr_ax = tmp;
      }
      if (tr_by < tr_ay) {
	tmp = tr_by;
	tr_by = tr_ay;
	tr_ay = tmp;
      }
      /* now clip box, if necessary */
      if (tr_ax < LINK->clipright && tr_bx > LINK->clipleft &&
	  tr_ay < LINK->cliptop && tr_by > LINK->clipbot) {
	if (root->tag == COMP) {
	  flatten_routing(root->UU.U1.c_d->routing_, LINK);
	  flatten_comp_2(root->UU.U1.c_d->data, LINK);
	} else
	  flatten_geom(root->UU.g_d->data, LINK);
      }

      root = root->next;   /* deal with its siblings */
      tr_ctm = old_matrix;   /* restore transformation matrix */
    }

  RECOVER(try1);
    if (P_escapecode == 10)
      _Escape(P_escapecode);
    else {
      show_error("Error in procedure flatten_comp_2", false);
      _Escape(10);
    }
  ENDTRY(try1);
}


Local void flatten_comp(struct LOC_flatten *LINK)
{
  tr_matrix old_mat;

  old_mat = tr_ctm;   /* Save it for later */
  pl_ident();   /* make identity matrix */

  flatten_routing(comp_cells->routing_, LINK);
  flatten_comp_2(comp_cells->data, LINK);
  flush_boxes(LINK->boxes, LINK);

  tr_ctm = old_mat;
}  /* call flatten_comp_2 with root of tree */


void flatten(void)
{
  struct LOC_flatten V;
  Char s[fidleng + 1];
  long slices_vert, slices_horiz, i;
  comp_list *compmbb;
  Char *TEMP;


  V.outfile = NULL;
  /* find COMP MBB, and infer grid from that */
  compmbb = get_c_cell();
  compmbb->data = comp_cells->data;
  set_c_bb(compmbb);

  slices_vert = (compmbb->ur.y - compmbb->ll.y) / clip_size + 1;
  slices_horiz = (compmbb->ur.x - compmbb->ll.x) / clip_size + 1;

  alpha_screen(CLR);
  printf("\n\n");
  m_alpha_on();
  printf("Enter name of file for flattened CIF: ");
  fgets(s, fidleng + 1, stdin);
  TEMP = strchr(s, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  if (V.outfile != NULL)
    V.outfile = freopen(s, "w", V.outfile);
  else
    V.outfile = fopen(s, "w");
  if (V.outfile == NULL)
    _EscIO(FileNotFound);
  fprintf(V.outfile, "DS 1 %d 2 ;\n", lambda_to_microns);
  fprintf(V.outfile, "9 %s ;\n", curr_comp_cell);
  fprintf(V.outfile, "(MBB;\n");
  fprintf(V.outfile, "B %ld %ld %ld %ld ;);\n",
	  labs((compmbb->ur.x - compmbb->ll.x) * 2),
	  labs((compmbb->ur.y - compmbb->ll.y) * 2),
	  compmbb->ur.x + compmbb->ll.x, compmbb->ur.y + compmbb->ll.y);
  V.number_of_boxes = 0;
  for (i = min_layer; i <= max_layer; i++)
    V.boxes[i - min_layer] = NULL;

  /*$if false$
    clipbot := compmbb^.ll.y;
    cliptop := clipbot + clip_size;
    for i := 1 to slices_vert do
       begin
          clipleft := compmbb^.ll.x;
          clipright := clipleft + clip_size;
          {nuke_boxes (boxes);}
          for j := 1 to slices_horiz do
            begin
               writeln ('(  horiz = ',j:0,'; vert = ',i:0,') ;');
               writeln (outfile, '(  horiz = ',j:0,'; vert = ',i:0,') ;');
               flatten_comp;
               clipleft  := clipleft + clip_size;
               clipright := clipleft + clip_size;
            end;
          clipbot := clipbot + clip_size;
          cliptop := clipbot + clip_size;
       end;
$end$*/
  V.clipleft = -INFIN;
  V.clipright = INFIN;
  V.clipbot = -INFIN;
  V.cliptop = INFIN;
  flatten_comp(&V);


  fprintf(V.outfile, "DF;\n");
  fprintf(V.outfile, "C 1 T 0 0;\n");
  fprintf(V.outfile, "E\n");
  if (V.outfile != NULL)
    fclose(V.outfile);
  V.outfile = NULL;
  printf("Number of boxes written = %ld\n", V.number_of_boxes);

  compmbb->data = NULL;
  recl_c_cell(&compmbb);
  if (V.outfile != NULL)
    fclose(V.outfile);
}

#undef clip_size


#define check_zero      true


/* Check for box intersection */
/* box "A" is the new box, box "B" is the old box */
Static clipconds check_boxes(box_rec *a, box_rec *b)
{
  boxes_checked++;
  if (a->llx > b->urx || a->lly > b->ury || a->urx < b->llx || a->ury < b->lly)
    return c_away;   /* Total rejection */
  else {
    if (a->llx == a->urx || a->lly == a->ury)   /* Zero size boxes suck. */
      printf("check_boxes: Warning: zero size box @ (%ld,%ld) n=%d b=%d\n",
	     renorm(a->llx), renorm(a->lly), a->node_, a->mybin);
    /* Old code for zero size boxes */
    if (a->llx >= b->llx && a->lly >= b->lly && a->urx <= b->urx &&
	a->ury <= b->ury)
	  /* Overlap */
	    return c_over;   /* Actually, total inclusion */
    else {
      if (a->llx == b->urx || a->lly == b->ury || a->urx == b->llx ||
	  a->ury == b->lly) {
	if (a->llx == b->urx && (a->lly == b->ury || a->ury == b->lly) ||
	    a->urx == b->llx && (a->ury == b->lly || a->lly == b->ury))
	  return c_corner;
	else
	  return c_edge;
      } else
	return c_over;
    }
  }
}

#undef check_zero


Static void dump_list(void)
{
  long i, FORLIM;

  FORLIM = maxnode;
  for (i = min_node; i < FORLIM; i++)
    printf("%3d", nodenumbers[i - min_node]);
  putchar('\n');
}


Static void show_statsf(FILE **out)
{
  Char s[81];
  extern long EXCP_LINE;
  long l_old;
  boolean debug, range;
  core_info_rec *WITH;

  get_date_string(s);
  fprintf(*out, "| %s %s on %s src:%s ;\n",
	  ext_version, wol_username, s, src_name);

  TRY(try2);   /* Check for debug and range checking */
    TRY(try3);
      P_escapecode = -1;
      goto _Ltry3;
    RECOVER2(try3,_Ltry3);
      ;
    ENDTRY(try3);
    /* Set debug error-line number */
    l_old = EXCP_LINE;
    /* Fake up a value range error */
    *s = '\0';
    s[1] = 'X';
    /* Generate an escape anyway (set error-line number) */
    P_escapecode = -1;
    goto _Ltry2;
  RECOVER2(try2,_Ltry2);
    if (P_escapecode != -8 && P_escapecode != -1)
      _Escape(P_escapecode);
    range = (P_escapecode == -8);
    debug = (EXCP_LINE != l_old);
  ENDTRY(try2);
  if (range)
    strcpy(s, "range on, ");
  else
    strcpy(s, "range off, ");
  if (debug)
    strcat(s, "debug on");
  else
    strcat(s, "debug off");

  fprintf(*out, "| %d N-transistors, %d P-transistors ;\n",
	  numntran, numptran);
  fprintf(*out, "| %d N2-transistors, %d P2-transistors ;\n",
	  numntran2, numptran2);
      /***/
  fprintf(*out, "| %ld total nodes (%ld orphans). ;\n",
	  total_nodes + orphan_nodes, orphan_nodes);
  fprintf(*out, "| Times (%s) wol To Xtr=%0.2f extract=%0.2f trans=%0.2f ;\n",
	  s, woltoxtrtime / 100.0, xtrtime / 100.0, trantime / 100.0);
  fprintf(*out,
    "| Maxnode=%d.  Boxes:  added=%ld clipped=%ld edges=%ld swallowed=%ld checked=%ld ;\n",
    maxnode, boxes_added, boxes_clipped, edges_clipped, boxes_swallow,
    boxes_checked);
  fprintf(*out, "| bins: w=%d h=%d #x=%d #y=%d ;\n",
	  binwidth, binheight, binx, biny);
  WITH = &core_info[core_box_kind];
  fprintf(*out,
    "| %d %s size=%ld news=%ld frees=%ld free=%ld used=%ld alloc=%ld rels=%ld ;\n",
    core_box_kind, WITH->name, WITH->size, WITH->news, WITH->frees,
    WITH->free, WITH->used, WITH->alloc, WITH->rels);
  WITH = &core_info[core_con_kind];
  fprintf(*out,
    "| %d %s size=%ld news=%ld frees=%ld free=%ld used=%ld alloc=%ld rels=%ld ;\n",
    core_box_kind, WITH->name, WITH->size, WITH->news, WITH->frees,
    WITH->free, WITH->used, WITH->alloc, WITH->rels);
  fprintf(*out, "| ;\n");
}


Static void show_stats(void)
{
  FILE *t, *TEMP;
  Char STR2[88];

  t = NULL;
  TEMP = stdout;
/* p2c: wol_xtract.text, line 619:
 * Note: Taking address of stdout; consider setting VarFiles = 0 [144] */
  show_statsf(&TEMP);
  printf("Logging stats to %sxtr.log...", WolLib);
  if (t != NULL) {
    sprintf(STR2, "%sxtr.log", WolLib);
    t = freopen(STR2, "a", t);
  } else {
    sprintf(STR2, "%sxtr.log", WolLib);
    t = fopen(STR2, "a");
  }
  if (t == NULL)
    _EscIO(FileNotFound);
  show_statsf(&t);
  if (t != NULL)
    fclose(t);
  t = NULL;
  printf("Done.\n");
  if (t != NULL)
    fclose(t);
}


Local long clip(long v, long low, long high)
{
  if (v > high)
    return high;
  else if (v < low)
    return low;
  else
    return v;
}


/* Setup the clipping information for the bins currently on the screen */
Static void screen_bins(point *bll, point *bur)
{
  /* Reverse transform the edges of the screen to find max/min bins */
  *bll = scale_down(zero_point);
  *bur = scale_down(change_to_point(RIGHT_OF_SCREEN, TOP_OF_SCREEN));
  /* *** KLUGE *** */
  bll->x = bll->x * 2 + 1;
  bll->y = bll->y * 2 + 1;
  bur->x = bur->x * 2 + 1;
  bur->y = bur->y * 2 + 1;

  /* Now convert from lambda to bins (and clip) */
  bll->x = clip(bll->x / binwidth, 0, binx - 1);
  bll->y = clip(bll->y / binheight, 0, biny - 1);
  bur->x = clip((bur->x - 1) / binwidth, 0, binx - 1);
  bur->y = clip((bur->y - 1) / binheight, 0, biny - 1);
}


Static void xor_node(long drnode)
{
  box_rec *p;
  long i;
  tr_matrix old_mat;
  point bll, bur;   /* Max/min bins on screen */
  long bx, by;
  box_rec *WITH;

  old_mat = tr_ctm;   /* Save it for later */
  make_matrix();   /* Scaling matrix */

  drnode = nodenumbers[drnode - min_node];

  screen_bins(&bll, &bur);

  small_graphics();   /* Save menu area!! */
  m_nocursor();
  m_colormode(m_xor);
  m_color(8);
  for (i = min_layer; i <= max_layer; i++) {
    if (i <= layer_via)
      set_layer(i);
    else
      set_layer(layer_diff);
    for (bx = bll.x; bx <= bur.x; bx++) {
      for (by = bll.y; by <= bur.y; by++) {
	p = bins[bx + by * binx].layers[i - min_layer].boxes;
	while (p != NULL) {
	  WITH = p;
	  if (nodenumbers[WITH->node_ - min_node] == drnode) {
	    tr_4(WITH->llx, WITH->lly, WITH->urx, WITH->ury);
	    m_fillrect(tr_ax, tr_ay, tr_bx, tr_by);
	    p = WITH->next;
	  } else
	    p = WITH->next;
	}
      }
    }
  }
  tr_ctm = old_mat;
  big_graphics();
}


/* Compute the area and capacitance of a node. */
Static void node_area(long checknode, long *area, double *capacitance)
{
  box_rec *p;
  long l, b, a;
  double area_factor;
  long FORLIM1;
  box_rec *WITH;

  checknode = nodenumbers[checknode - min_node];

  for (l = min_layer; l <= max_layer; l++) {
    a = 0;
    FORLIM1 = binmax;
    for (b = 0; b <= FORLIM1; b++) {
      p = bins[b].layers[l - min_layer].boxes;
      while (p != NULL) {
	WITH = p;
	if (nodenumbers[WITH->node_ - min_node] == checknode)
	  a += (WITH->urx - WITH->llx) * (WITH->ury - WITH->lly);
	p = WITH->next;
      }
    }
    area[l - min_layer] = a;
  }
  /* now calculate capacitances */
  *capacitance = 0.0;
  area_factor = lambda_to_microns / 100.0 * (lambda_to_microns / 100.0);
  *capacitance += area_factor * area[layer_poly - min_layer] * 0.67e-4;
  *capacitance += area_factor * area[layer_poly2 - min_layer] * 0.67e-4;
      /*wild guess*/
  *capacitance += area_factor * area[layer_diff - min_layer] * 3.6e-4;
  *capacitance += area_factor * area[layer_metal - min_layer] * 0.31e-4;
  *capacitance += area_factor * area[layer_metal2 - min_layer] * 0.21e-4;
  *capacitance += area_factor * area[layer_ds - min_layer] * 3.9e-4;
  *capacitance += area_factor * area[layer_dw - min_layer] * 2.1e-4;
  *capacitance += area_factor * area[layer_dpw - min_layer] * 9.6e-4;
  *capacitance += area_factor * area[layer_dps - min_layer] * 9.6e-4;
  *capacitance += area_factor * area[layer_dp2s - min_layer] * 9.6e-4;
      /*wild guess*/
  *capacitance += area_factor * area[layer_dp2w - min_layer] * 9.6e-4;
      /*wild guess*/
  *capacitance += area_factor * area[layer_dpp2 - min_layer] * 4.8e-4;   /***/
  /*  these should not be required
  capacitance := capacitance + area_factor * area[layer_sel] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_via] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_well] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_cutp] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_cuta] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_glass] * 0E-4;
  capacitance := capacitance + area_factor * area[layer_cut2] * 0E-4;*/
  /***/
}


/* Compute the transistor connectivity of a node. */
Static void node_connect(long node_, long *Pgate, long *Pgarea,
  long *Psource, long *Ngate, long *Ngarea, long *Nsource, long *P2gate,
  long *P2garea, long *P2source, long *N2gate, long *N2garea,
  long *N2source)
{
  long i, FORLIM;
  tran_rec *WITH;

  node_ = nodenumbers[node_ - min_node];

  *Pgate = 0;
  *Pgarea = 0;
  *Psource = 0;
  FORLIM = numptran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ptran[i];
    if (node_ == WITH->gate) {
      (*Pgate)++;
      *Pgarea += WITH->area;
    }
    if (WITH->acount > 0 && node_ == WITH->actives[0] ||
	WITH->acount > 1 && node_ == WITH->actives[1] ||
	WITH->acount > 2 && node_ == WITH->actives[2] ||
	WITH->acount > 3 && node_ == WITH->actives[3] ||
	WITH->acount > 4 && node_ == WITH->actives[4])
	  /* MAS */
	    (*Psource)++;
  }

  *P2gate = 0;
  *P2garea = 0;
  *P2source = 0;
  FORLIM = numptran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ptran2[i];
    if (node_ == WITH->gate)   /***/
    {  /***/
      (*P2gate)++;   /***/
      *P2garea += WITH->area;   /***/
    }  /***/
    if (WITH->acount > 0 && node_ == WITH->actives[0] ||
	WITH->acount > 1 && node_ == WITH->actives[1] ||
	WITH->acount > 2 && node_ == WITH->actives[2] ||
	WITH->acount > 3 && node_ == WITH->actives[3] ||
	WITH->acount > 4 && node_ == WITH->actives[4])
	  /***/
	    (*P2source)++;
    /***/
    /***/
    /***/
    /***/
    /***/
  }
  /***/
  /***/

  *Ngate = 0;
  *Ngarea = 0;
  *Nsource = 0;
  FORLIM = numntran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ntran[i];
    if (node_ == WITH->gate) {
      (*Ngate)++;
      *Ngarea += WITH->area;
    }
    if (WITH->acount > 0 && node_ == WITH->actives[0] ||
	WITH->acount > 1 && node_ == WITH->actives[1] ||
	WITH->acount > 2 && node_ == WITH->actives[2] ||
	WITH->acount > 3 && node_ == WITH->actives[3] ||
	WITH->acount > 4 && node_ == WITH->actives[4])
	  /*MAS */
	    (*Nsource)++;
  }

  *N2gate = 0;
  *N2garea = 0;
  *N2source = 0;
  FORLIM = numntran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ntran2[i];
    if (node_ == WITH->gate)   /***/
    {  /***/
      (*N2gate)++;   /***/
      *N2garea += WITH->area;   /***/
    }  /***/
    if (WITH->acount > 0 && node_ == WITH->actives[0] ||
	WITH->acount > 1 && node_ == WITH->actives[1] ||
	WITH->acount > 2 && node_ == WITH->actives[2] ||
	WITH->acount > 3 && node_ == WITH->actives[3] ||
	WITH->acount > 4 && node_ == WITH->actives[4])
	  /***/
	    (*N2source)++;
    /***/
    /***/
    /*MAS */
    /***/
    /***/
    /***/
  }
  /***/
  /***/
}


/* Local variables for FiNd_nOdE_By_lAyEr: */
struct LOC_FiNd_nOdE_By_lAyEr {
  long l;
  boolean found;
} ;

Local void checkbin(long bx, long by, long x, long y,
		    struct LOC_FiNd_nOdE_By_lAyEr *LINK)
{
  box_rec *p, *WITH;

  if ((unsigned)bx >= binx || (unsigned)by >= biny)
    return;
  p = bins[bx + by * binx].layers[LINK->l - min_layer].boxes;
  while (p != NULL && !LINK->found) {
    WITH = p;
    if (x >= WITH->llx && x <= WITH->urx && y >= WITH->lly && y <= WITH->ury) {
      /*write('found: node=',node:1);*/
      node_found_by_layer = nodenumbers[WITH->node_ - min_node];
      /*writeln(' node_found_by_layer=',node_found_by_layer:1);*/
      LINK->found = true;
      /*              escape(11);  { Indicate "I found it" */
    } else
      p = WITH->next;
  }
}


/* Find a node connected to the current point one layer at a time. */
/* Generate escape(11) if found, return normally if not found. */
/* If we found a node, then the global variable Node_Found_By_Layer */
/* will be set. */
Static boolean FiNd_nOdE_By_lAyEr(long x, long y, long l_)
{
  struct LOC_FiNd_nOdE_By_lAyEr V;
  long bx, by;
  boolean xedge, yedge;

  V.l = l_;
  V.found = false;
  /* Which bin is the pen in? */
  bx = (x * 2 + 1) / binwidth;   /* *** KLUGE *** */
  by = (y * 2 + 1) / binheight;

  checkbin(bx, by, x, y, &V);
  if (V.found)
    return V.found;
  xedge = (bx * binwidth == x);
  if (xedge)
    checkbin(bx - 1, by, x, y, &V);
  if (V.found)
    return V.found;
  yedge = (by * binheight == y);
  if (!yedge)
    return V.found;
  checkbin(bx, by - 1, x, y, &V);
  if (!V.found) {
    if (xedge)
      checkbin(bx - 1, by - 1, x, y, &V);
  }
  return V.found;
}


Static long find_a_node(point where)
{
  node_found_by_layer = -1;

  /* Check layers in a specific order */
  /* (prevent well & select from stealing all points) */
  TRY(try4);
    if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_poly)) {
      if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_poly2)) {   /***/
	if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_d)) {
	  if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_ds)) {
	    if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_dw)) {
	      if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_dsw)) {
		if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_metal)) {
		  if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_metal2)) {
		    if (!FiNd_nOdE_By_lAyEr(where.x, where.y, layer_sel))
			  /* Just for fun?? */
			    FiNd_nOdE_By_lAyEr(where.x, where.y, layer_well);
		  }
		}
	      }
	    }
	  }
	}
      }
    }

  RECOVER(try4);
    if (P_escapecode != 11)
      _Escape(P_escapecode);
  ENDTRY(try4);
  /*writeln('Find_a_node is returning: ',node_found_by_layer:1);*/
  return node_found_by_layer;

  /* Layers ignored here: */
  /* Transistor gate regions have been merged into the layer_poly and layer_poly2 lists */
  /***/
  /* layer_dps, layer_dpw layer_dp2s, layer_dp2w*/
  /***/
  /* There are no cuts in the data structure */
  /* layer_via, layer_cutp, layer_cuta, layer_cut2 */
  /***/
  /* Diffusion should have been converted to layer_d*** */
  /* layer_diff */
  /* These are illegal diffusion layers */
  /* layer_dpsw, layer_dp, layer_dp2, layer_dp2sw, layer_dpp2, layer_dpp2sw */
  /***/
  /* Tetrode structures are treated as two transistors in series; i.e. , the following*/
  /***/
  /* layers are converted to diffusion: */
  /***/
  /* layer_dpp2s, layer_dpp2w */
  /***/
  /* Glass is not interesting either */
  /* layer_glass */

  /* Oh, well there is no connection */
}


/* Show statistics/flash a node */
Static void show_and_flash_a_node(long node_)
{
  area_arr area;
  long Pgate, Pgarea, Psource, Ngate, Ngarea, Nsource, P2gate, P2garea,
	P2source, N2gate, N2garea, N2source;
  double gate_capacitance, capacitance;
  long i;
  long ta;
  tablet_info t;
  boolean was_near, down;

  if (node_ >= 0)
    node_ = nodenumbers[node_ - min_node];

  if (node_ >= 0) {
    if (!strcmp(m_machine, "9836C")) {
      alpha_screen(CLR);
      putchar('\n');
    }
    m_alpha_on();
    printf("Node: %d\n", node_);

    printf("Transistor fanout: ");
    node_connect(node_, &Pgate, &Pgarea, &Psource, &Ngate, &Ngarea, &Nsource,
		 &P2gate, &P2garea, &P2source, &N2gate, &N2garea, &N2source);
    /* ***KLUGE*** */
    Pgarea /= 4;
    Ngarea /= 4;
    P2garea /= 4;
    N2garea /= 4;
    gate_capacitance = (Pgarea + Ngarea + P2garea + N2garea) *
		       (lambda_to_microns / 100.0) *
		       (lambda_to_microns / 100.0) * (6.2e-4 - 0.44e-4);

    printf("%d Pg (%d square lambda) %d Ps ", Pgate, Pgarea, Psource);
    printf("%d P2g (%d square lambda) %d P2s ", P2gate, P2garea, P2source);
    printf("%d Ng (%d square lambda) %d Ns.\n", Ngate, Ngarea, Nsource);
    printf("%d N2g (%d square lambda) %d N2s.\n", N2gate, N2garea, N2source);
    if (show_node_info && node_ >= 0) {
      printf("Node area: ");
      node_area(node_, area, &capacitance);
      ta = 0;
      for (i = min_layer; i <= max_layer; i++)
	ta += area[i - min_layer];
      printf("%ld square lambda (nearly).  Capacitance = %0.5fpF\n",
	     ta, gate_capacitance + capacitance);
    }

    printf("\nPress or lift pen to stop flashing.");

    t = get_pen();   /* Toast a few pen cycles */
    t = get_pen();
    was_near = false;
    down = false;
    do {
      /* Only call get_pen in this part to prevent screen screwups */
      xor_node(node_);
      t = get_pen();
      m_cursor(t.x, t.y);
      if (t.near_)
	was_near = true;
      if (t.depressed)
	down = true;
      /* Call check_pen in this part to allow zoom/pan */
      xor_node(node_);
      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));
    return;
  }
  alpha_screen(CLR);
  putchar('\n');
  m_alpha_on();
  printf("No such node!!!\n");
}


void mp_Xtract(point start)
{
  long n;

  start = scale_down(start);

  if (!in_extract) {
    show_message("\n\nCan't light up nodes, you must extract first.", true);
    printf("position: %ld,%ld (Lambda).\n", start.x, start.y);
    return;
  }
  n = find_a_node(start);
  printf("Find_a_node returned: %d\n", n);
  if (n >= 0)
    show_and_flash_a_node(n);
  else {
    printf("No node found.\n");
    printf("position: %ld,%ld (Lambda).\n", start.x, start.y);
  }
}


void xtr_flash(void)
{
  Char s[21];
  long i, p;
  Char *STR2;
  Char *TEMP;

  if (!strcmp(m_machine, "9836C"))
    alpha_screen(CLR);
  m_alpha_on();
  printf("\nEnter node number to flash: ");
  fgets(s, 21, stdin);
  TEMP = strchr(s, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  TRY(try5);
    i = strtol(s, &STR2, 10);
    p = STR2 - s + 1;
    show_and_flash_a_node(i);
  RECOVER(try5);
    if (P_escapecode != -10)
      _Escape(P_escapecode);
  ENDTRY(try5);
  m_alpha_off();
}


void draw_boxes(void)
{
  box_rec *p;
  hcon_rec *h;
  vcon_rec *v;
  long x, y, i;
  tr_matrix old_mat;
  point bll, bur;   /* Max/min bins on screen */
  long bx, by;
  box_rec *WITH;
  Char STR1[256];
  Char STR2[256];
  Char STR3[256];
  hcon_rec *WITH1;
  vcon_rec *WITH2;

  old_mat = tr_ctm;   /* Save it for later */
  make_matrix();   /* Scaling matrix */

  screen_bins(&bll, &bur);

  small_graphics();   /* Save menu area!! */
  m_nocursor();
  clear_screen();
  m_colormode(m_over);

  /* Draw the boxes */
  for (i = min_layer; i <= max_layer; i++) {
    if (i <= layer_via)
      set_layer(i);
    else
      set_layer(layer_diff);
    for (bx = bll.x; bx <= bur.x; bx++) {
      for (by = bll.y; by <= bur.y; by++) {
	p = bins[bx + by * binx].layers[i - min_layer].boxes;
	while (p != NULL) {
	  WITH = p;
	  tr_4(WITH->llx, WITH->lly, WITH->urx, WITH->ury);
	  m_drawrect(tr_ax, tr_ay, tr_bx, tr_by);
	  /*m_drawrect(llx*ext_zoom,lly*ext_zoom,urx*ext_zoom,ury*ext_zoom);*/
	  /*writeln('node=',node:1,' nodenumbers^[node]=',nodenumbers^[node]:1);*/
	  if (i != layer_sel && i != layer_glass) {
	    if (xtr_debug) {
	      sprintf(STR3, "%d.%d",
		      nodenumbers[WITH->node_ - min_node], WITH->node_);
	      m_centerstr((tr_ax + tr_bx) / 2, (tr_ay + tr_by) / 2 + 3, NULL,
			  STR3);
	    } else {
	      sprintf(STR3, "%d", nodenumbers[WITH->node_ - min_node]);
	      m_centerstr((tr_ax + tr_bx) / 2, (tr_ay + tr_by) / 2 + 3, NULL,
			  STR3);
	    }
	  }
	  p = WITH->next;   /*p^.*/
	}
      }
    }
  }
  /* Draw the Connections.. */
  if (xtr_debug) {
    for (i = min_layer; i <= max_layer; i++) {
      if (i <= layer_via)
	set_layer(i);
      else
	set_layer(layer_diff);
      for (bx = bll.x; bx <= bur.x; bx++) {
	for (by = bll.y; by <= bur.y; by++) {
	  /* Compute south-west corner of this box */
	  x = bx * binwidth;
	  y = by * binheight;
	  /*tr_2(x,y); x := tr_ax; y := tr_ay;*/

	  h = bins[bx + by * binx].layers[i - min_layer].south;
	  v = bins[bx + by * binx].layers[i - min_layer].west;
	  while (h != NULL) {
	    WITH1 = h;
	    tr_4(WITH1->lowx, y, WITH1->highx, y);
	    tr_by += 3;
	    m_drawrect(tr_ax, tr_ay, tr_bx, tr_by);
	    if (i != layer_sel && i != layer_glass) {
	      sprintf(STR2, "%d.%d",
		      nodenumbers[WITH1->node_ - min_node], WITH1->node_);
	      m_centerstr((tr_ax + tr_bx) / 2, (tr_ay + tr_by) / 2 + 3, NULL,
			  STR2);
	    }
	    h = WITH1->next;   /*h^.*/
	  }
	  while (v != NULL) {
	    WITH2 = v;
	    tr_4(x, WITH2->lowy, x, WITH2->highy);
	    tr_bx += 3;
	    m_drawrect(tr_ax, tr_ay, tr_bx, tr_by);
	    if (i != layer_sel && i != layer_glass) {
	      sprintf(STR1, "%d.%d",
		      nodenumbers[WITH2->node_ - min_node], WITH2->node_);
	      m_centerstr((tr_ax + tr_bx) / 2, (tr_ay + tr_by) / 2 + 3, NULL,
			  STR1);
	    }
	    v = WITH2->next;   /*v^.*/
	  }
	}
      }
    }
  }
  tr_ctm = old_mat;
  big_graphics();
}


Static void clip_(box_rec *clipbox, box_rec *inbox, box_rec **outlist)
{
  box_rec *newbox;

  *outlist = NULL;
  boxes_clipped++;

  if (inbox->llx < clipbox->llx && clipbox->llx < inbox->urx)
  {  /*writeln('Clip left');*/
    edges_clipped++;
    newbox = new_box();;
    *newbox = *inbox;
    newbox->urx = clipbox->llx;
    newbox->next = *outlist;
    *outlist = newbox;
    inbox->llx = clipbox->llx;
  }

  if (inbox->lly < clipbox->lly && clipbox->lly < inbox->ury)
  {  /*writeln('Clip bottom');*/
    edges_clipped++;
    newbox = new_box();
    *newbox = *inbox;
    newbox->ury = clipbox->lly;
    newbox->next = *outlist;
    *outlist = newbox;
    inbox->lly = clipbox->lly;
  }

  if (inbox->llx < clipbox->urx && clipbox->urx < inbox->urx)
  {  /*writeln('Clip right');*/
    edges_clipped++;
    newbox = new_box();
    *newbox = *inbox;
    newbox->llx = clipbox->urx;
    newbox->next = *outlist;
    *outlist = newbox;
    inbox->urx = clipbox->urx;
  }

  if (inbox->lly < clipbox->ury && clipbox->ury < inbox->ury)
  {  /*writeln('Clip top');*/
    edges_clipped++;
    newbox = new_box();
    *newbox = *inbox;
    newbox->lly = clipbox->ury;
    newbox->next = *outlist;
    *outlist = newbox;
    inbox->ury = clipbox->ury;
  }
  if (*outlist == NULL)
    boxes_swallow++;
}


/* Inputs:
{     clist - list of things to clip against
{     ilist - list of things to clip
{     inside- list of boxes that were inside clist
{     outside-list of boxes that are outside clist
{*/
Static void clip_diff(box_rec *clist, box_rec *ilist, box_rec **inside,
		      box_rec **outside)
{
  box_rec *cliststart, *olist;   /* temporary outside list */
  box_rec *ilistn;
  boolean is_outside;

  cliststart = clist;

  while (ilist != NULL) {
    clist = cliststart;
    ilistn = ilist->next;
    is_outside = true;   /* Assume this box is outside everyone else */
    while (clist != NULL) {
      switch (check_boxes(ilist, clist)) {

      case c_away:
      case c_corner:
      case c_edge:
	clist = clist->next;
	break;

      case c_over:
	clip_(clist, ilist, &olist);
	/* Add ILIST^ to the INSIDE list */
	ilist->next = *inside;
	*inside = ilist;
	is_outside = false;   /* make sure others know this */
	/* Clip list of outside boxes */
	clip_diff(clist->next, olist, inside, outside);
	/* Eat current box */
	clist = NULL;
	break;

      default:
	printf("Bad check_boxes\n");
	break;
      }
    }
    if (is_outside) {   /* add to outside list */
      ilist->next = *outside;
      *outside = ilist;
    }
    ilist = ilistn;
  }
}


Static void vcon_insert(vcon_rec *v, long vx, layer_rec *liststart)
{
  box_rec *bp, *WITH1;

  bp = liststart->boxes;
  while (bp != NULL) {
    WITH1 = bp;
    if (WITH1->llx == vx && v->lowy < WITH1->ury && v->highy > WITH1->lly)
	  /* The box touches the edge */
	    equiv(bp->node_, v->node_);
    /* Overlap is good */
    bp = bp->next;
  }

  v->next = liststart->west;
  liststart->west = v;
}


Static void hcon_insert(hcon_rec *h, long hy, layer_rec *liststart)
{
  box_rec *bp, *WITH1;

  bp = liststart->boxes;
  while (bp != NULL) {
    WITH1 = bp;
    if (WITH1->lly == hy && h->lowx < WITH1->urx && h->highx > WITH1->llx)
	  /* The box touches the edge */
	    equiv(bp->node_, h->node_);
    /* Overlap is good */
    bp = bp->next;
  }

  h->next = liststart->south;
  liststart->south = h;
}


/* Just insert a box into a list of boxes. */
/* Nothing inserted here should be ZERO size. */
Static void boxonly_insert(box_rec *boxp, box_rec **liststart)
{
  box_rec *list, *boxo, *boxn;
  boolean ok_add;

  /* What kind of thing is this? */
  if (boxp->llx == boxp->urx || boxp->lly == boxp->ury)   /* connection */
    printf("\007Eeeeeeeek.  Zero size box in BOXONLY_INSERT.\n");

  ok_add = true;
  list = *liststart;

  while (list != NULL) {
    switch (check_boxes(boxp, list)) {

    case c_away:
      list = list->next;
      break;

    case c_corner:
      /*writeln('CORNER-CORNER');*/
      list = list->next;
      break;

    case c_edge:
      if (global_debug)
	printf("E");
      equiv(boxp->node_, list->node_);
      list = list->next;
      break;

    case c_over:
      if (global_debug)
	printf("O");
      equiv(boxp->node_, list->node_);
      clip_(list, boxp, &boxo);
      /* Clip outside boxes */
      while (boxo != NULL) {
	boxn = boxo->next;
	boxonly_insert(boxo, &list->next);
	boxo = boxn;
      }
      ok_add = false;   /* Eat current box */
      list = NULL;   /* all done, get me out */
      break;

    default:
      printf("Bad check_boxes\n");
      break;
    }
  }
  if (ok_add) {
    boxp->next = *liststart;
    *liststart = boxp;
  } else
    free(boxp);
}


/* Converts zero size boxes to connections */
Static void box_insert(box_rec *boxp, layer_rec *liststart)
{
  vcon_rec *v;
  hcon_rec *h;
  long bx, by;
  box_rec *WITH;
  vcon_rec *WITH1;
  hcon_rec *WITH2;

  /* Re-compute x and y bin numbers */
  by = boxp->mybin / binx;
  bx = boxp->mybin - by * binx;

  WITH = boxp;
  /* ELSE, we have a real box */


  if (WITH->llx == WITH->urx) {   /* Vertical connection */
    if (WITH->lly != WITH->ury) {   /* Oky-doky boxy */
      if (WITH->llx == bx * binwidth) {
	    /* Check that the X value is right */
	      v = new_vcon();
	v->next = NULL;
	v->node_ = boxp->node_;
	v->mybin = boxp->mybin;
	v->lowy = boxp->lly;
	v->highy = boxp->ury;
	vcon_insert(v, WITH->llx, liststart);
      } else
	printf("vcon: Bad Zero size box @%ld,%ld n=%d b=%d=(%d,%d)\n",
	       renorm(boxp->llx), renorm(boxp->lly), boxp->node_, boxp->mybin,
	       bx, by);
    } else
      printf("Attempt to insert zero-zero size box, ignored.\n");

    free(boxp);
    goto _L1;
  }
  if (WITH->lly == WITH->ury) {   /* Horizontal connection */
    /* Check that the Y value is right */
    if (WITH->lly == by * binheight) {
      h = new_hcon();
      h->next = NULL;
      h->node_ = boxp->node_;
      h->mybin = boxp->mybin;
      h->lowx = boxp->llx;
      h->highx = boxp->urx;
      hcon_insert(h, WITH->lly, liststart);
    } else
      printf("hcon: Bad Zero size box @%ld,%ld n=%d b=%d=(%d,%d)\n",
	     renorm(boxp->llx), renorm(boxp->lly), boxp->node_, boxp->mybin,
	     bx, by);

    free(boxp);
    goto _L1;
  }
  /* Quick check for connections */
  if (boxp->llx == bx * binwidth) {
    /*writeln('Check for Vcon to the west');*/
    v = liststart->west;
    while (v != NULL) {
      WITH1 = v;
      if (WITH1->lowy < boxp->ury && WITH1->highy > boxp->lly)  /* Overlap */
	equiv(v->node_, boxp->node_);
      v = WITH1->next;
    }
  }

  if (boxp->lly == by * binheight) {
    /*writeln('Check for Hcon to the south');*/
    h = liststart->south;
    while (h != NULL) {
      WITH2 = h;
      if (WITH2->lowx < boxp->urx && WITH2->highx > boxp->llx)  /* Overlap */
	equiv(h->node_, boxp->node_);
      h = WITH2->next;
    }
  }

  /* Now actually insert the box */
  boxonly_insert(boxp, &liststart->boxes);
_L1: ;   /* Return */
}


/* Local variables for insert_diff: */
struct LOC_insert_diff {
  box_rec *dif_arr[layer_dpp2sw - layer_d + 1];   /***/
  long bin, bin_x, bin_y;
} ;

Local void clip_it(long clip, long base, long out,
		   struct LOC_insert_diff *LINK)
{
  box_rec *tmp;

  tmp = LINK->dif_arr[base - layer_d];
  LINK->dif_arr[base - layer_d] = NULL;
  LINK->dif_arr[out - layer_d] = NULL;   /* outside */
  /* inside */
  clip_diff(bins[LINK->bin].layers[clip - min_layer].boxes, tmp,
	    &LINK->dif_arr[out - layer_d], &LINK->dif_arr[base - layer_d]);
}

Local void do_insert(long dlayer, long real_layer, boolean retain_node,
		     struct LOC_insert_diff *LINK)
{
  box_rec *bp, *bn, *s;

  bp = LINK->dif_arr[dlayer - layer_d];
  while (bp != NULL) {
    bn = bp->next;
    if (!retain_node)
      bp->node_ = nextnodenum();
    /*writeln('do_insert: ',bp^.urx:5,bin*binwidth:5);*/
    if (bp->urx == LINK->bin_x * binwidth) {
      s = new_box();
      *s = *bp;
      s->llx = LINK->bin_x * binwidth;
      s->mybin = LINK->bin + 1;
      /*if retain_node then write('DVcon');*/
      box_insert(s, &bins[LINK->bin + 1].layers[real_layer - min_layer]);
    }
    if (bp->ury == LINK->bin_y * binheight) {
      s = new_box();
      *s = *bp;
      s->lly = LINK->bin_y * binheight;
      s->mybin = LINK->bin + binx;
      /*if retain_node then write('DHcon');*/
      box_insert(s, &bins[LINK->bin + binx].layers[real_layer - min_layer]);
    }
    box_insert(bp, &bins[LINK->bin].layers[real_layer - min_layer]);
    bp = bn;
  }
}

Local void do_insert2(long dlayer, long rl1, long rl2, boolean retain_node,
		      struct LOC_insert_diff *LINK)
{
  box_rec *bp, *bn, *bp2, *s, *s2;

  bp = LINK->dif_arr[dlayer - layer_d];
  while (bp != NULL) {
    bn = bp->next;
    if (!retain_node)
      bp->node_ = nextnodenum();
    /*writeln('do_insert2: ',bp^.urx:5,bin*binwidth:5);*/
    if (bp->urx == LINK->bin_x * binwidth) {
      s = new_box();
      *s = *bp;
      s->llx = LINK->bin_x * binwidth;
      s->mybin = LINK->bin + 1;
      s2 = new_box();
      *s2 = *s;
      box_insert(s, &bins[LINK->bin + 1].layers[rl1 - min_layer]);
      box_insert(s2, &bins[LINK->bin + 1].layers[rl2 - min_layer]);
    }
    if (bp->ury == LINK->bin_y * binheight) {
      s = new_box();
      *s = *bp;
      s->lly = LINK->bin_y * binheight;
      s->mybin = LINK->bin + binx;
      s2 = new_box();
      *s2 = *s;
      box_insert(s, &bins[LINK->bin + binx].layers[rl1 - min_layer]);
      box_insert(s2, &bins[LINK->bin + binx].layers[rl2 - min_layer]);
    }
    bp2 = new_box();
    *bp2 = *bp;
    box_insert(bp2, &bins[LINK->bin].layers[rl1 - min_layer]);
    box_insert(bp, &bins[LINK->bin].layers[rl2 - min_layer]);
    bp = bn;
  }
}


/* Inputs:                                                                  */
/*     BOXP - pointer to A diffusion box to insert                          */
/*                                                                          */
/*  This routine splits the diffusion box into parts based on the           */
/*  interaction with WELL, POLY, POLY2, and SELECT.  This results in 16 lists */
/***/
/*  which are then inserted into various diffusion lists.                   */

Static void insert_diff(box_rec *boxp, boolean retain_node)
{
  struct LOC_insert_diff V;
  long i;
  box_rec *bp, *bn, *WITH;


  V.bin = boxp->mybin;
  V.bin_x = V.bin % binx + 1;
/* p2c: wol_xtract.text, line 1545:
 * Note: Using % for possibly-negative arguments [317] */
  V.bin_y = V.bin / binx + 1;

  boxp->next = NULL;

  for (i = layer_d; i <= layer_dpp2sw; i++)   /***/
    V.dif_arr[i - layer_d] = NULL;

  /* Start by putting whole list into dif_arr[0] */
  V.dif_arr[0] = boxp;

  clip_it(layer_well, layer_d, layer_dw, &V);   /***/
  clip_it(layer_sel, layer_d, layer_ds, &V);   /***/
  clip_it(layer_sel, layer_dw, layer_dsw, &V);   /***/
  clip_it(layer_poly, layer_d, layer_dp, &V);   /***/
  clip_it(layer_poly2, layer_d, layer_dp2, &V);   /***/
  clip_it(layer_poly, layer_ds, layer_dps, &V);   /***/
  clip_it(layer_poly, layer_dw, layer_dpw, &V);   /***/
  clip_it(layer_poly, layer_dsw, layer_dpsw, &V);   /***/
  clip_it(layer_poly2, layer_ds, layer_dp2s, &V);   /***/
  clip_it(layer_poly2, layer_dw, layer_dp2w, &V);   /***/
  clip_it(layer_poly2, layer_dsw, layer_dp2sw, &V);   /***/
  clip_it(layer_poly2, layer_dp, layer_dpp2, &V);   /***/
  clip_it(layer_poly2, layer_dps, layer_dpp2s, &V);   /***/
  clip_it(layer_poly2, layer_dpw, layer_dpp2w, &V);   /***/
  clip_it(layer_poly2, layer_dpsw, layer_dpp2sw, &V);   /***/

  /* clip_it(layer_poly,layer_d,  layer_dp);   { Statistically worse?? */
  /* clip_it(layer_well,layer_d,  layer_dw);     { YES by ~1%--Whee! */
  /* clip_it(layer_well,layer_dp, layer_dpw);
  { clip_it(layer_sel, layer_d,  layer_ds);
  { clip_it(layer_sel, layer_dw, layer_dsw);
  { clip_it(layer_sel, layer_dp, layer_dps);
  { clip_it(layer_sel, layer_dpw,layer_dpsw); {*/

  /* Now we have 16 lists of boxes that we must insert into lists. */
  /***/
  /* They also all need to get new node numbers. */

  if (V.dif_arr[0] != NULL) {   /* No-select, No-well, No-poly, No-poly2 */
    if (V.dif_arr[layer_ds - layer_d] != NULL) {
      WITH = V.dif_arr[layer_ds - layer_d];
      printf("Select-active diode @ (%ld,%ld)\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      if (do_output)
	fprintf(ntk_out, "| Select-active diode @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    }
    /* Make everyone ground */
    if (retain_node) {
      /*write('GndCut');*/
      equiv(V.dif_arr[0]->node_, GROUND);
    } else {
      boxp = V.dif_arr[0];
      while (boxp != NULL) {
	boxp->node_ = GROUND;
	boxp = boxp->next;
      }
    }
    if (short_diodes)
      do_insert2(layer_d, layer_dw, layer_ds, true, &V);
    else
      do_insert(layer_d, layer_dw, true, &V);
  }
  /***/

  if (V.dif_arr[layer_ds - layer_d] != NULL)
  {   /* SELECT, No-well, No-poly, No-poly2*/
    /*if retain_node then write('Ins Ds');*/
    do_insert(layer_ds, layer_ds, retain_node, &V);
  }
  /***/

  if (V.dif_arr[layer_dw - layer_d] != NULL)
	/* No-select,    WELL, No-poly, No-poly2*/
	  do_insert(layer_dw, layer_dw, retain_node, &V);
  /***/

  if (V.dif_arr[layer_dsw - layer_d] != NULL)
  {   /*    SELECT,    WELL, No-poly, No-poly2 */
    if (short_diodes)
      do_insert2(layer_dsw, layer_dw, layer_well, retain_node, &V);
    else
      do_insert2(layer_dsw, layer_dsw, layer_well, retain_node, &V);
  }
  /***/

  if (V.dif_arr[layer_dp - layer_d] != NULL)
  {   /* No-select, No-well, No-poly2,    POLY */
/* p2c: wol_xtract.text, line 1635:
 * Note: Character >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1637:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1637:
 * Note: WRITE statement contains color/attribute characters [203] */
    WITH = V.dif_arr[layer_dp - layer_d];
    printf("\213 P1 transistor in substrate region @ (%ld,%ld)\200\210\n",
	   (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	   (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    if (do_output)
      fprintf(ntk_out, "P1 transistor in substrate region @ (%ld,%ld) ;\n",
	      (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	      (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    bp = V.dif_arr[layer_dp - layer_d];
    while (bp != NULL) {
      bn = bp->next;
      free(bp);
      bp = bn;
    }
  }
  /***/

  if (V.dif_arr[layer_dp2 - layer_d] != NULL)
      /* No-select, No-well, No-poly,    POLY2 */
      {  /***/
    WITH = V.dif_arr[layer_dp2 - layer_d];   /***/
    printf("\213P2 transistor in substrate region @ (%ld,%ld)\200\210\n",
	   (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	   (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	/***/
    if (do_output)   /***/
      fprintf(ntk_out, "P2 transistor in substrate region @ (%ld,%ld) ;\n",
	      (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	      (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    /***/
    /***/
    /***/
    bp = V.dif_arr[layer_dp2 - layer_d];   /***/
    while (bp != NULL)   /***/
    {  /***/
      bn = bp->next;   /***/
      free(bp);   /***/
      bp = bn;   /***/
    }  /***/
  }  /***/
  /***/
  /***/
  /***/
/* p2c: wol_xtract.text, line 1656:
 * Note: Character >= 128 encountered [281] */
  /***/
  /***/
/* p2c: wol_xtract.text, line 1658:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1658:
 * Note: WRITE statement contains color/attribute characters [203] */

  if (V.dif_arr[layer_dpp2 - layer_d] != NULL)
      /* No-select, No-well, POLY,    POLY2 */
      {  /***/
    WITH = V.dif_arr[layer_dpp2 - layer_d];   /***/
    printf("\213Tetrode transistor in substrate region @ (%ld,%ld)\200\210\n",
	   (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	   (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	/***/
    if (do_output)   /***/
      fprintf(ntk_out,
	      "Tetrode transistor in substrate region @ (%ld,%ld) ;\n",
	      (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	      (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    /***/
    /***/
    /***/
    bp = V.dif_arr[layer_dpp2 - layer_d];   /***/
    while (bp != NULL)   /***/
    {  /***/
      bn = bp->next;   /***/
      free(bp);   /***/
      bp = bn;   /***/
    }  /***/
  }  /***/
  /***/
  /***/
  /***/
/* p2c: wol_xtract.text, line 1677:
 * Note: Character >= 128 encountered [281] */
  /***/
  /***/
/* p2c: wol_xtract.text, line 1679:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1679:
 * Note: WRITE statement contains color/attribute characters [203] */

  if (V.dif_arr[layer_dpp2s - layer_d] != NULL)
      /* SELECT, No-well, POLY,    POLY2 */
      {  /***/
    do_insert(layer_dpp2s, layer_ds, retain_node, &V);   /***/
    if (retain_node) {   /***/
      WITH = V.dif_arr[layer_dpp2s - layer_d];
      printf("\213Contact to N-tetrode-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	  /***/
      if (do_output)   /***/
	fprintf(ntk_out, "Contact to N-tetrode-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      /***/
      /***/
      /***/
    }
    /***/
    /***/
/* p2c: wol_xtract.text, line 1700:
 * Note: Character >= 128 encountered [281] */
    /***/
    /***/
/* p2c: wol_xtract.text, line 1702:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1702:
 * Note: WRITE statement contains color/attribute characters [203] */
    /***/
  }  /***/
  /***/

  if (V.dif_arr[layer_dpp2w - layer_d] != NULL)
      /* No-select, WELL, POLY,    POLY2 */
      {  /***/
    do_insert(layer_dpp2w, layer_dw, retain_node, &V);   /***/
    if (retain_node) {   /***/
      WITH = V.dif_arr[layer_dpp2w - layer_d];
      printf("\213Contact to P-tetrode-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	  /***/
      if (do_output)   /***/
	fprintf(ntk_out, "Contact to P-tetrode-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      /***/
      /***/
      /***/
    }
    /***/
    /***/
/* p2c: wol_xtract.text, line 1716:
 * Note: Character >= 128 encountered [281] */
    /***/
    /***/
/* p2c: wol_xtract.text, line 1718:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1718:
 * Note: WRITE statement contains color/attribute characters [203] */
    /***/
  }  /***/
  /***/

  if (V.dif_arr[layer_dps - layer_d] != NULL)
  {   /*    SELECT, No-well, No-poly2    POLY */
    do_insert(layer_dps, layer_dps, retain_node, &V);
    if (retain_node) {
/* p2c: wol_xtract.text, line 1732:
 * Note: Character >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1734:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1734:
 * Note: WRITE statement contains color/attribute characters [203] */
      WITH = V.dif_arr[layer_dps - layer_d];
      printf("\213Contact to N-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      if (do_output)
	fprintf(ntk_out, "Contact to N-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    }
  }
  /***/

  if (V.dif_arr[layer_dp2s - layer_d] != NULL)
      /*    SELECT, No-well, No-poly,    POLY2 */
      {  /***/
    do_insert(layer_dp2s, layer_dp2s, retain_node, &V);   /***/
    if (retain_node) {   /***/
      WITH = V.dif_arr[layer_dp2s - layer_d];
      printf("\213Contact to N-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	  /***/
      if (do_output)   /***/
	fprintf(ntk_out, "Contact to N-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      /***/
      /***/
      /***/
    }
    /***/
    /***/
/* p2c: wol_xtract.text, line 1748:
 * Note: Character >= 128 encountered [281] */
    /***/
    /***/
/* p2c: wol_xtract.text, line 1750:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1750:
 * Note: WRITE statement contains color/attribute characters [203] */
    /***/
  }  /***/
  /***/

  if (V.dif_arr[layer_dpw - layer_d] != NULL)
  {   /* No-select, No-poly2    WELL,    POLY */
    do_insert(layer_dpw, layer_dpw, retain_node, &V);
    if (retain_node) {
/* p2c: wol_xtract.text, line 1764:
 * Note: Character >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1766:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1766:
 * Note: WRITE statement contains color/attribute characters [203] */
      WITH = V.dif_arr[layer_dpw - layer_d];
      printf("\213Contact to P-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      if (do_output)
	fprintf(ntk_out, "Contact to P-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    }
  }
  /***/

  if (V.dif_arr[layer_dp2w - layer_d] != NULL)
      /* No-select, No-poly    WELL,    POLY2 */
      {  /***/
    do_insert(layer_dp2w, layer_dp2w, retain_node, &V);   /***/
    if (retain_node) {   /***/
      WITH = V.dif_arr[layer_dp2w - layer_d];
      printf("\213Contact to P2-transistor @ (%ld,%ld)\200\210\n",
	     (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	     (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	  /***/
      if (do_output)   /***/
	fprintf(ntk_out, "Contact to P2-transistor @ (%ld,%ld) ;\n",
		(renorm(WITH->llx) + renorm(WITH->urx)) / 2,
		(renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      /***/
      /***/
      /***/
    }
    /***/
    /***/
/* p2c: wol_xtract.text, line 1780:
 * Note: Character >= 128 encountered [281] */
    /***/
    /***/
/* p2c: wol_xtract.text, line 1782:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1782:
 * Note: WRITE statement contains color/attribute characters [203] */
    /***/
  }  /***/
  /***/

  if (V.dif_arr[layer_dpsw - layer_d] != NULL)
  {   /* No-poly2,   SELECT,    WELL,    POLY */
/* p2c: wol_xtract.text, line 1794:
 * Note: Character >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1796:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1796:
 * Note: WRITE statement contains color/attribute characters [203] */
    WITH = V.dif_arr[layer_dpsw - layer_d];
    printf("\213Transistor in Ohmic contact to well @ (%ld,%ld)\200\210\n",
	   (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	   (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    if (do_output)
      fprintf(ntk_out, "Transistor in Ohmic contact to well @ (%ld,%ld) ;\n",
	      (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	      (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    bp = V.dif_arr[layer_dpsw - layer_d];
    while (bp != NULL) {
      bn = bp->next;
      free(bp);
      bp = bn;
    }
  }
  /***/
  /* was dpw -- MAS */

  if (V.dif_arr[layer_dp2sw - layer_d] != NULL)
      /* No-poly,   SELECT,    WELL,    POLY2 */
      {  /***/
    WITH = V.dif_arr[layer_dp2sw - layer_d];   /***/
    printf("\213Transistor in Ohmic contact to well @ (%ld,%ld)\200\210\n",
	   (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	   (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
	/***/
    if (do_output)   /***/
      fprintf(ntk_out, "Transistor in Ohmic contact to well @ (%ld,%ld) ;\n",
	      (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	      (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
    /***/
    /***/
    /***/
    bp = V.dif_arr[layer_dp2sw - layer_d];   /***/
    while (bp != NULL)   /***/
    {  /***/
      bn = bp->next;   /***/
      free(bp);   /***/
      bp = bn;   /***/
    }  /***/
  }  /***/
  /***/
  /***/
  /***/
/* p2c: wol_xtract.text, line 1815:
 * Note: Character >= 128 encountered [281] */
  /***/
  /***/
/* p2c: wol_xtract.text, line 1817:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1817:
 * Note: WRITE statement contains color/attribute characters [203] */

  if (V.dif_arr[layer_dpp2sw - layer_d] == NULL)
      /* POLY,   SELECT,    WELL,    POLY2 */
      {  /***/
    return;
  }  /***/
  /***/
  /***/
  /***/
/* p2c: wol_xtract.text, line 1836:
 * Note: Character >= 128 encountered [281] */
  /***/
  /***/
/* p2c: wol_xtract.text, line 1838:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1838:
 * Note: WRITE statement contains color/attribute characters [203] */
  WITH = V.dif_arr[layer_dpp2sw - layer_d];   /***/
  printf("\213Transistor in Ohmic contact to well @ (%ld,%ld)\200\210\n",
	 (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	 (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
      /***/
  if (do_output)   /***/
    fprintf(ntk_out, "Transistor in Ohmic contact to well @ (%ld,%ld) ;\n",
	    (renorm(WITH->llx) + renorm(WITH->urx)) / 2,
	    (renorm(WITH->lly) + renorm(WITH->ury)) / 2);
  /***/
  /***/
  /***/
  bp = V.dif_arr[layer_dpp2sw - layer_d];   /***/
  while (bp != NULL)   /***/
  {  /***/
    bn = bp->next;   /***/
    free(bp);   /***/
    bp = bn;   /***/
  }  /***/
}


/* Cut up a box and put it in different bins */
Static void choosebin(long layer, box_rec *inbox, box_rec **outlist)
{
  box_rec *hlist, *hp;   /* horizontal list of boxes */
  box_rec *newbox;
  long bllx, blly, burx, bury;   /* Which bins (x & y) */
  box_rec *WITH;

  hlist = NULL;
  *outlist = NULL;
  bllx = inbox->llx / binwidth;
  blly = inbox->lly / binheight;
  if (layer != layer_diff) {
    burx = inbox->urx / binwidth;
    bury = inbox->ury / binheight;
  } else {
    burx = (inbox->urx - 1) / binwidth;
    bury = (inbox->ury - 1) / binheight;
  }
  if (burx > binx || bury > biny) {
    printf("\007\213Your universe is TOO SMALL, clipping box...\200\210\n");
    burx = binx;
    bury = biny;
  }
/* p2c: wol_xtract.text, line 1877:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1877:
 * Note: WRITE statement contains color/attribute characters [203] */
  /* Things could be optimized for the case where the box is inside one bin */
  while (bllx < burx) {   /* Split the box in X */
    newbox = new_box();
    *newbox = *inbox;
    newbox->mybin = bllx;
    bllx++;
    newbox->urx = bllx * binwidth;
    inbox->llx = newbox->urx;
    newbox->next = hlist;
    hlist = newbox;
  }
  /* Add main box to list */
  inbox->mybin = burx;
  inbox->next = hlist;
  hlist = inbox;

  while (blly < bury) {
    hp = hlist;
    while (hp != NULL) {
      newbox = new_box();
      *newbox = *hp;
      newbox->mybin += binx * blly;
      newbox->ury = (blly + 1) * binheight;
      hp->lly = newbox->ury;
      newbox->next = *outlist;
      *outlist = newbox;
      hp = hp->next;
    }
    blly++;
  }
  WITH = hlist;

  /* Look for 0 width and 0 height box */
  if (WITH->llx == WITH->urx && WITH->lly == WITH->ury) {
    hp = hlist;
    free(hp);
    hlist = hlist->next;
  }
  /* Add last horizontal row to outlist */
  hp = hlist;
  while (hp != NULL) {
    newbox = hp->next;   /* Next box in list */
    hp->next = *outlist;
    hp->mybin += binx * bury;
    *outlist = hp;
    hp = newbox;
  }
}


Static void add_box(long layer, long llx, long lly, long urx, long ury)
{
  box_rec *p, *p2, *blist, *bn;
  long t;
  box_rec *WITH;

  boxes_added++;
  if (llx == urx || lly == ury) {
    printf("\213Warning: attempt to ADD_BOX zero size box, ignored.\200\210\n");
    goto _L1;
  }
/* p2c: wol_xtract.text, line 1944:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 1944:
 * Note: WRITE statement contains color/attribute characters [203] */
  p = new_box();
  if (llx > urx) {
    t = urx;
    urx = llx;
    llx = t;
  }
  if (lly > ury) {
    t = ury;
    ury = lly;
    lly = t;
  }
  p->llx = llx;
  p->lly = lly;
  p->urx = urx;
  p->ury = ury;
  if (layer == layer_diff)
    p->node_ = -1;
  else
    p->node_ = nextnodenum();
  p->next = NULL;

  /* Now split the box into bins */
  choosebin(layer, p, &blist);

  while (blist != NULL) {
    WITH = blist;
    bn = WITH->next;   /*blist^.*/
    switch (layer) {

    case layer_diff:
      insert_diff(blist, false);
      break;

    case layer_cutp:  /* For a CUTP, insert a METAL and POLY box */
      p2 = new_box();
      *p2 = *blist;
      box_insert(p2, &bins[WITH->mybin].layers[layer_poly - min_layer]);
      box_insert(blist, &bins[WITH->mybin].layers[layer_metal - min_layer]);
      break;

    case layer_cut2:   /***/
      p2 = new_box();   /***/
      *p2 = *blist;   /***/
      box_insert(p2, &bins[WITH->mybin].layers[layer_poly2 - min_layer]);
	  /***/
      box_insert(blist, &bins[WITH->mybin].layers[layer_metal - min_layer]);
	  /***/
      break;
      /* For a CUT2, insert a METAL and POLY2 box */
      /***/
      /***/

    case layer_cuta:  /* For a CUTA, insert a METAL and DIFF box */
      /* Only insert this into the diffusion lists if not==zero */
      if (WITH->llx != WITH->urx && WITH->lly != WITH->ury) {
	p2 = new_box();
	*p2 = *blist;
	insert_diff(p2, true);
      }
      /*else write(' Cuta/Diff eaten ');*/
      box_insert(blist, &bins[WITH->mybin].layers[layer_metal - min_layer]);
      break;

    case layer_via:  /* For a VIA, insert a METAL and METAL2 box */
      p2 = new_box();
      *p2 = *blist;
      box_insert(p2, &bins[WITH->mybin].layers[layer_metal2 - min_layer]);
      box_insert(blist, &bins[WITH->mybin].layers[layer_metal - min_layer]);
      break;

    default:
      box_insert(blist, &bins[WITH->mybin].layers[layer - min_layer]);
      break;
    }/* case */
    blist = bn;
  }
_L1: ;
}


/* Find active connections and compute area of gate */
Static void find_active(tran_rec *tran, long alayer, long gate_layer)
{
  box_rec *bp, *ap, *bpn;
  long node_;

  tran->area = 0;
  tran->acount = 0;
  bp = tran->boxes;
  while (bp != NULL) {
    if (tran->area == 0) {
      tran->x = (bp->urx + bp->llx) / 2;
      tran->y = (bp->ury + bp->lly) / 2;
    }
    tran->area += (bp->urx - bp->llx) * (bp->ury - bp->lly);

    ap = bins[bp->mybin].layers[alayer - min_layer].boxes;
    while (ap != NULL) {
      node_ = nodenumbers[ap->node_ - min_node];
      switch (check_boxes(bp, ap)) {

      case c_away:
      case c_corner:
	/* blank case */
	break;

      case c_edge:
      case c_over:
	if ((tran->acount <= 0 || node_ != tran->actives[0]) &&
	    (tran->acount <= 1 || node_ != tran->actives[1]) &&
	    (tran->acount <= 2 || node_ != tran->actives[2]) &&
	    (tran->acount <= 3 || node_ != tran->actives[3]) &&
	    (tran->acount <= 4 || node_ != tran->actives[4]))
	{   /* MAS */
	  if (tran->acount > 4)
	    printf("\213Too many actives (>4).\200\210\n");
	  else {
	    tran->actives[tran->acount] = node_;
	    tran->acount++;
	  }
/* p2c: wol_xtract.text, line 2042:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 2042:
 * Note: WRITE statement contains color/attribute characters [203] */
	}
	/* node already present */
	break;

      default:
	printf("Bad check_boxes\n");
	break;
      }
      ap = ap->next;
    }
    bp = bp->next;
  }
  /* Now stick all of the tran.boxes into the appropriate POLY list to connect the gate */
  bp = tran->boxes;
  while (bp != NULL) {
    bpn = bp->next;
    box_insert(bp, &bins[bp->mybin].layers[gate_layer - min_layer]);   /***/
    bp = bpn;
  }
}


Static void look_for_it(long tran_layer, long *numtran, tran_rec *trans)
{
  box_rec *bp, *bpn;
  long i, b, bx, by;   /* boundaries of bin */
  hcon_rec *h, *hn;
  vcon_rec *v, *vn;
  long FORLIM;
  layer_rec *WITH;
  vcon_rec *WITH1;
  hcon_rec *WITH2;

  *numtran = 0;
  FORLIM = binmax;
  for (b = 0; b <= FORLIM; b++) {
    WITH = &bins[b].layers[tran_layer - min_layer];
    bx = b % binx * binwidth;
/* p2c: wol_xtract.text, line 2081:
 * Note: Using % for possibly-negative arguments [317] */
    by = b / binx * binheight;

    /* Convert connection records to boxes */
    v = WITH->west;   /*bins^[b].layers[tran_layer].*/
    while (v != NULL) {
      WITH1 = v;
      vn = WITH1->next;
      bp = new_box();
      bp->node_ = WITH1->node_;
      bp->mybin = WITH1->mybin;
      bp->lly = WITH1->lowy;
      bp->ury = WITH1->highy;
      bp->llx = bx;
      bp->urx = bx;
      bp->next = WITH->boxes;
      WITH->boxes = bp->next;
      free(v);
      v = vn;
    }
    WITH->west = NULL;
    h = WITH->south;   /*bins^[b].layers[tran_layer].*/
    while (h != NULL) {
      WITH2 = h;
      hn = WITH2->next;
      bp = new_box();
      bp->node_ = WITH2->node_;
      bp->mybin = WITH2->mybin;
      bp->llx = WITH2->lowx;
      bp->urx = WITH2->highx;
      bp->lly = by;
      bp->ury = by;
      bp->next = WITH->boxes;
      WITH->boxes = bp->next;
      free(h);
      h = hn;
    }
    WITH->south = NULL;

    bp = WITH->boxes;   /*bins^[b].layers[tran_layer].*/
    while (bp != NULL) {
      bpn = bp->next;
      i = 0;
      while (i < *numtran) {
	if (trans[i].gate == nodenumbers[bp->node_ - min_node]) {
	  bp->next = trans[i].boxes;
	  trans[i].boxes = bp;
	  i = 30000;
	} else
	  i++;
      }
      if (i != 30000) {
	trans[*numtran].gate = nodenumbers[bp->node_ - min_node];
	bp->next = NULL;
	trans[*numtran].boxes = bp;
	trans[*numtran].acount = 0;
	if (*numtran < max_tran)
	  (*numtran)++;
	else
	  printf("\007\213Too many transistors.\200\210\n");
      }
      bp = bpn;
    }
    /*bins^[b].layers[layer_dpw].*/
    WITH->boxes = NULL;
  }

/* p2c: wol_xtract.text, line 2142:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 2142:
 * Note: WRITE statement contains color/attribute characters [203] */
}


#define noise           false


Static void find_transistors(void)
{
  long i, FORLIM;
  tran_rec *WITH;

  mashnodes();
  equivforce();

  printf("Looking for P-transistors.\n");
  look_for_it(layer_dpw, &numptran, ptran);

  printf("Looking for N-transistors.\n");
  look_for_it(layer_dps, &numntran, ntran);

  printf("Looking for P2-transistors.\n");   /***/
  look_for_it(layer_dp2w, &numptran2, ptran2);   /***/

  printf("Looking for N2-transistors.\n");   /***/
  look_for_it(layer_dp2s, &numntran2, ntran2);   /***/

  printf("%d N-transistors., %d P-transistors.\n", numntran, numptran);
  printf("%d N2-transistors., %d P2-transistors.\n", numntran2, numptran2);
      /***/
  printf("Looking for active connections to transistors.\n");

  FORLIM = numptran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ptran[i];
    find_active(&ptran[i], layer_dw, layer_poly);
  }
  FORLIM = numntran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ntran[i];
    find_active(&ntran[i], layer_ds, layer_poly);
  }

  FORLIM = numptran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ptran2[i];
    find_active(&ptran2[i], layer_dw, layer_poly2);
  }
  /***/
  FORLIM = numntran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ntran2[i];
    find_active(&ntran2[i], layer_ds, layer_poly2);
  }
  /***/

  equivforce();   /* force poly-gate insertions to show up */

  FORLIM = numptran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ptran[i];
    WITH->gate = nodenumbers[WITH->gate - min_node];
    WITH->actives[0] = nodenumbers[WITH->actives[0] - min_node];
    WITH->actives[1] = nodenumbers[WITH->actives[1] - min_node];
    WITH->actives[2] = nodenumbers[WITH->actives[2] - min_node];
    WITH->actives[3] = nodenumbers[WITH->actives[3] - min_node];
    WITH->actives[4] = nodenumbers[WITH->actives[4] - min_node];
  }
  FORLIM = numntran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ntran[i];
    WITH->gate = nodenumbers[WITH->gate - min_node];
    WITH->actives[0] = nodenumbers[WITH->actives[0] - min_node];
    WITH->actives[1] = nodenumbers[WITH->actives[1] - min_node];
    WITH->actives[2] = nodenumbers[WITH->actives[2] - min_node];
    WITH->actives[3] = nodenumbers[WITH->actives[3] - min_node];
    WITH->actives[4] = nodenumbers[WITH->actives[4] - min_node];
  }

  FORLIM = numptran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ptran2[i];
    WITH->gate = nodenumbers[WITH->gate - min_node];   /***/
    WITH->actives[0] = nodenumbers[WITH->actives[0] - min_node];   /***/
    WITH->actives[1] = nodenumbers[WITH->actives[1] - min_node];   /***/
    WITH->actives[2] = nodenumbers[WITH->actives[2] - min_node];   /***/
    WITH->actives[3] = nodenumbers[WITH->actives[3] - min_node];   /***/
    WITH->actives[4] = nodenumbers[WITH->actives[4] - min_node];   /***/
  }
  /***/
  /***/
  FORLIM = numntran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ntran2[i];
    WITH->gate = nodenumbers[WITH->gate - min_node];   /***/
    WITH->actives[0] = nodenumbers[WITH->actives[0] - min_node];   /***/
    WITH->actives[1] = nodenumbers[WITH->actives[1] - min_node];   /***/
    WITH->actives[2] = nodenumbers[WITH->actives[2] - min_node];   /***/
    WITH->actives[3] = nodenumbers[WITH->actives[3] - min_node];   /***/
    WITH->actives[4] = nodenumbers[WITH->actives[4] - min_node];   /***/
  }
  /***/
  /***/

  /*$if noise$
   { must renorm all of these if they are to work }
   for i:=0 to numptran-1 do with ptran^[i] do
      begin
         writeln('Ptran #',i:2,' gate=',gate:3,' numa=',acount:1,
                ' a1=',actives[0]:3,' a2=',actives[1]:3,
                'area=',area:3,' x=',x:5,' y=',y:5);
      end;
   for i:=0 to numntran-1 do with ntran^[i] do
      begin
         writeln('Ntran #',i:2,' gate=',gate:3,' numa=',acount:1,
                ' a1=',actives[0]:3,' a2=',actives[1]:3,
                'area=',area:3,' x=',x:5,' y=',y:5);
      end;
   writeln(numntran:1,' N-transistors., ',numptran:1,' P-transistors.');

   for i:=0 to numptran2-1 do with ptran2^[i] do                            {*}
      begin                                                                 {*}
         writeln('Ptran2 #',i:2,' gate=',gate:3,' numa=',acount:1,          {*}
                ' a1=',actives[0]:3,' a2=',actives[1]:3,                    {*}
                'area=',area:3,' x=',x:5,' y=',y:5);                        {*}
      end;                                                                  {*}
   for i:=0 to numntran2-1 do with ntran2^[i] do                            {*}
      begin                                                                 {*}
         writeln('Ntran2 #',i:2,' gate=',gate:3,' numa=',acount:1,          {*}
                ' a1=',actives[0]:3,' a2=',actives[1]:3,                    {*}
                'area=',area:3,' x=',x:5,' y=',y:5);                        {*}
      end;                                                                  {*}
   writeln(numntran2:1,' N2-transistors., ',numptran2:1,' P2-transistors.');{*}
$end$*/

}

#undef noise


/* Local variables for dump_nodes: */
struct LOC_dump_nodes {
  /* total_nodes : integer;
  orphan_nodes : integer;  { now globals */
  boolean dumped[max_node - min_node + 1];
} ;

Local void dump(long *node_, struct LOC_dump_nodes *LINK)
{
  long a;

  do {   /* Definitely find the lowest node for this guy!! */
    a = *node_;
    *node_ = nodenumbers[*node_ - min_node];
  } while (a != *node_);
  if (LINK->dumped[*node_ - min_node])
    return;
  total_nodes++;
  LINK->dumped[*node_ - min_node] = true;
  fprintf(ntk_out, "s 1 _%d ; \n", *node_);
  /*'| layer=',i:1,' area=',' hah! ;');*/
}


Static void dump_nodes(void)
{
  struct LOC_dump_nodes V;
  long i, b, l, n;
  box_rec *bp;
  long FORLIM;
  tran_rec *WITH;
  box_rec *WITH1;

  total_nodes = 0;
  orphan_nodes = 0;

  for (i = min_node; i <= max_node; i++)
    V.dumped[i - min_node] = false;

  printf("P1 transistors,");
  FORLIM = numptran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ptran[i];
    dump(&WITH->gate, &V);
    if (WITH->acount == 0)
      fprintf(ntk_out, "s 1 __%d ;\n", WITH->gate);
    if (WITH->acount > 0)
      dump(WITH->actives, &V);
    if (WITH->acount > 1)
      dump(&WITH->actives[1], &V);
    WITH->area = 1;   /**** KLUGE ****/
    fprintf(ntk_out, "p %ld _%d", WITH->area, WITH->gate);
    switch (WITH->acount) {

    case 0:
      fprintf(ntk_out, " __%d __%d ; | One contact", WITH->gate, WITH->gate);
      break;

    case 1:
      fprintf(ntk_out, " _%d _%d ; | Two contact",
	      WITH->actives[0], WITH->actives[0]);
      break;

    case 2:
      fprintf(ntk_out, " _%d _%d", WITH->actives[0], WITH->actives[1]);
      break;

    case 3:
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
      dump(&WITH->actives[2], &V);
      fprintf(ntk_out, "p %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
      fprintf(ntk_out, "p %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
      break;

    case 4:
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
      dump(&WITH->actives[2], &V);
      dump(&WITH->actives[3], &V);
      fprintf(ntk_out, "p %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
      fprintf(ntk_out, "p %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[3]);
      fprintf(ntk_out, "p %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
      fprintf(ntk_out, "p %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[3]);
      fprintf(ntk_out, "p %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[2], WITH->actives[3]);
      break;

    default:
      fprintf(ntk_out, " _%d _%d ; | Six or more contact",
	      WITH->actives[0], WITH->actives[1]);
      break;
    }
    fprintf(ntk_out, " ; | (%ld,%ld) ;\n", renorm(WITH->x), renorm(WITH->y));
	/* *** KLUGE *** */
  }
  printf("N1 transistors,");
  FORLIM = numntran;
  for (i = 0; i < FORLIM; i++) {
    WITH = &ntran[i];
    dump(&WITH->gate, &V);
    if (WITH->acount == 0)
      fprintf(ntk_out, "s 1 __%d ;\n", WITH->gate);
    if (WITH->acount > 0)
      dump(WITH->actives, &V);
    if (WITH->acount > 1)
      dump(&WITH->actives[1], &V);
    fprintf(ntk_out, "n 1 _%d", WITH->gate);
    switch (WITH->acount) {

    case 0:
      fprintf(ntk_out, " __%d __%d ; | One contact", WITH->gate, WITH->gate);
      break;

    case 1:
      fprintf(ntk_out, " _%d _%d ; | Two contact",
	      WITH->actives[0], WITH->actives[0]);
      break;

    case 2:
      fprintf(ntk_out, " _%d _%d", WITH->actives[0], WITH->actives[1]);
      break;

    case 3:
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
      dump(&WITH->actives[2], &V);
      fprintf(ntk_out, "n %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
      fprintf(ntk_out, "n %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
      break;

    case 4:
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
      dump(&WITH->actives[2], &V);
      dump(&WITH->actives[3], &V);
      fprintf(ntk_out, "n %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
      fprintf(ntk_out, "n %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[3]);
      fprintf(ntk_out, "n %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
      fprintf(ntk_out, "n %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[3]);
      fprintf(ntk_out, "n %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[2], WITH->actives[3]);
      break;

    default:
      fprintf(ntk_out, " _%d _%d ; | Six or more contact",
	      WITH->actives[0], WITH->actives[1]);
      break;
    }
    fprintf(ntk_out, " ; | (%ld,%ld) ;\n", renorm(WITH->x), renorm(WITH->y));
	/* *** KLUGE *** */
  }

  printf("P2 transistors,");   /***/
  FORLIM = numptran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ptran2[i];
    dump(&WITH->gate, &V);   /***/
    if (WITH->acount == 0)   /***/
      fprintf(ntk_out, "s 1 __%d ;\n", WITH->gate);
    if (WITH->acount > 0)   /***/
      dump(WITH->actives, &V);
    if (WITH->acount > 1)   /***/
      dump(&WITH->actives[1], &V);
    fprintf(ntk_out, "P %ld _%d", WITH->area, WITH->gate);   /***/
    switch (WITH->acount) {   /***/

    case 0:   /***/
      fprintf(ntk_out, " __%d __%d ; | One contact", WITH->gate, WITH->gate);
      break;

    case 1:   /***/
      fprintf(ntk_out, " _%d _%d ; | Two contact",
	      WITH->actives[0], WITH->actives[0]);
      break;

    case 2:   /***/
      fprintf(ntk_out, " _%d _%d", WITH->actives[0], WITH->actives[1]);
      break;

    case 3:  /***/
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
	  /***/
      dump(&WITH->actives[2], &V);   /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
	  /***/
      break;
      /***/

    case 4:   /***/
      /***/
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
	  /***/
      dump(&WITH->actives[2], &V);   /***/
      dump(&WITH->actives[3], &V);   /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[3]);
	  /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[3]);
	  /***/
      /***/
      fprintf(ntk_out, "P %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[2], WITH->actives[3]);
	  /***/
      break;
      /***/
      /***/

    default:   /***/
      fprintf(ntk_out, " _%d _%d ; | Six or more contact",
	      WITH->actives[0], WITH->actives[1]);
      break;
    }/***/
    fprintf(ntk_out, " ; | (%ld,%ld) ;\n", renorm(WITH->x), renorm(WITH->y));
	/* *** KLUGE *** */
    /***/
  }
  /***/
  /***/
  printf("N2 transistors,");   /***/
  FORLIM = numntran2;
  for (i = 0; i < FORLIM; i++) {   /***/
    WITH = &ntran2[i];
    dump(&WITH->gate, &V);   /***/
    if (WITH->acount == 0)   /***/
      fprintf(ntk_out, "s 1 __%d ;\n", WITH->gate);
    if (WITH->acount > 0)   /***/
      dump(WITH->actives, &V);
    if (WITH->acount > 1)   /***/
      dump(&WITH->actives[1], &V);
    fprintf(ntk_out, "N 1 _%d", WITH->gate);   /***/
    switch (WITH->acount) {   /***/

    case 0:   /***/
      fprintf(ntk_out, " __%d __%d ; | One contact", WITH->gate, WITH->gate);
      break;

    case 1:   /***/
      fprintf(ntk_out, " _%d _%d ; | Two contact",
	      WITH->actives[0], WITH->actives[0]);
      break;

    case 2:   /***/
      fprintf(ntk_out, " _%d _%d", WITH->actives[0], WITH->actives[1]);
      break;

    case 3:  /***/
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
	  /***/
      dump(&WITH->actives[2], &V);   /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
	  /***/
      break;
      /***/

    case 4:   /***/
      /***/
      fprintf(ntk_out, " _%d _%d ;\n", WITH->actives[0], WITH->actives[1]);
	  /***/
      dump(&WITH->actives[2], &V);   /***/
      dump(&WITH->actives[3], &V);   /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[0], WITH->actives[3]);
	  /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[2]);
	  /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d ;\n",
	      WITH->area, WITH->gate, WITH->actives[1], WITH->actives[3]);
	  /***/
      /***/
      fprintf(ntk_out, "N %ld _%d _%d _%d",
	      WITH->area, WITH->gate, WITH->actives[2], WITH->actives[3]);
	  /***/
      break;
      /***/
      /***/

    default:   /***/
      fprintf(ntk_out, " _%d _%d ; | Six or more contact",
	      WITH->actives[0], WITH->actives[1]);
      break;
    }/***/
    fprintf(ntk_out, " ; | (%ld,%ld) ;\n", renorm(WITH->x), renorm(WITH->y));
	/* *** KLUGE *** */
    /***/
  }
  /***/
  /***/

  printf("Orphan nodes, ");
  fprintf(ntk_out, "| Orphan nodes ;\n");
  FORLIM = binmax;
  for (b = 0; b <= FORLIM; b++) {
    for (l = min_layer; l <= max_layer; l++) {
      if (l != layer_sel && l != layer_glass) {
	bp = bins[b].layers[l - min_layer].boxes;
	while (bp != NULL) {
	  WITH1 = bp;
	  n = nodenumbers[WITH1->node_ - min_node];
	  if (!V.dumped[n - min_node]) {
	    orphan_nodes++;
	    V.dumped[n - min_node] = true;   /* ***KLUGE*** */
	    /*   ' (',(llx+urx) div 2:1,',',(lly+ury) div 2:1,') ;'); */
	    /* ' (',(renorm(llx)+renorm(urx)) div 2:1,',',
	          (renorm(lly)+renorm(ury)) div 2:1,') ;');  */
	    fprintf(ntk_out, "s 1 _%d ; | %s (%ld,%ld) ;\n",
		    WITH1->node_, layer_names[l - min_layer],
		    renorm(WITH1->llx), renorm(WITH1->lly));
		/* ***KLUGE*** */
	  }
	  bp = WITH1->next;
	}
      }
    }
  }
  /*   writeln(ntk_out,'| ',numntran:1,' N-transistors, ',numptran:1,' P-transistors ;');      */
  /*    writeln(ntk_out,'| ',numntran2:1,' N2-transistors, ',numptran2:1,' P2-transistors ;');  */
  /***/
  /*  writeln(ntk_out,'| ',total_nodes+orphan_nodes:1,' total nodes (',                        */
  /*                    orphan_nodes:1,' orphans). ;');  */
  show_statsf(&ntk_out);

  printf("Done.\n");   /***/

  /* writeln(numntran:1,' N-transistors, ',numptran:1,' P-transistors');
     writeln(numntran2:1,' N2-transistors, ',numptran2:1,' P2-transistors');*/
  /*  writeln(total_nodes+orphan_nodes:1,' total nodes (',orphan_nodes:1,' orphans)');*/
}


Static void add_to_list(box_rec **head, box_rec *element)
{
  /* creates a list in INCREASING order of areas */
  box_rec *tmp_head, *prev_head;
  long area;

  /*writeln ('adding box on layer: ', element^.layer);*/
  if (*head == NULL) {
    *head = element;
    return;
  }
  tmp_head = *head;
  prev_head = *head;
  area = (element->urx - element->llx) * (element->ury - element->lly);
  while (tmp_head != NULL &&
	 (tmp_head->urx - tmp_head->llx) * (tmp_head->ury - tmp_head->lly) <
	 area) {
    prev_head = tmp_head;
    tmp_head = tmp_head->next;
  }
  if (tmp_head == *head) {
    element->next = *head;
    *head = element;
  } else {
    element->next = tmp_head;
    prev_head->next = element;
  }
}


Static void fix_this_shit(void)
{
  box_rec *bp;
  long i, b;
  hcon_rec *h;
  vcon_rec *v;
  long FORLIM1;
  layer_rec *WITH;
  vcon_rec *WITH1;
  hcon_rec *WITH2;
  box_rec *WITH3;

  for (i = min_layer; i <= max_layer; i++) {
    FORLIM1 = binmax;
    for (b = 0; b <= FORLIM1; b++) {
      WITH = &bins[b].layers[i - min_layer];
      v = WITH->west;   /*bins^[b].layers[tran_layer].*/
      while (v != NULL) {
	WITH1 = v;
	WITH1->lowy = (WITH1->lowy - 1) / 2;
	WITH1->highy = (WITH1->highy - 1) / 2;
	v = WITH1->next;
      }
      h = WITH->south;   /*bins^[b].layers[tran_layer].*/
      while (h != NULL) {
	WITH2 = h;
	WITH2->lowx = (WITH2->lowx - 1) / 2;
	WITH2->highx = (WITH2->highx - 1) / 2;
	h = WITH2->next;
      }

      bp = WITH->boxes;   /*bins^[b].layers[tran_layer].*/
      while (bp != NULL) {
	WITH3 = bp;
	WITH3->llx = (WITH3->llx - 1) / 2;
	WITH3->lly = (WITH3->lly - 1) / 2;
	WITH3->urx = (WITH3->urx - 1) / 2;
	WITH3->ury = (WITH3->ury - 1) / 2;
	bp = WITH3->next;
      }
    }
  }
}


/* Local variables for do_xtr: */
struct LOC_do_xtr {
  long number_of_boxes;
  sort_arr boxes;

  sort_arr new_boxes;   /* for each cell, build up temporary boxes here */
} ;

/*  thus, boxes will only be sorted on a cell by cell basis */

Local void preappend(box_rec **new_boxes, box_rec **boxes,
		     struct LOC_do_xtr *LINK)
{
  /* takes lists in new_boxes, and pre-appends them to those in boxes */
  long i;
  box_rec *tmp, *tmpnext;

  for (i = min_layer; i <= max_layer; i++) {
    /* push each list onto the global list, reversing order*/
    tmp = new_boxes[i - min_layer];
    while (tmp != NULL) {
      tmpnext = tmp->next;
      tmp->next = boxes[i - min_layer];
      boxes[i - min_layer] = tmp;
      tmp = tmpnext;
    }
  }
}


Local void slurp(long layer, struct LOC_do_xtr *LINK)
{
  box_rec *tmp, *tmpnext;
  long c;
  box_rec *WITH;

  global_debug = false;

  c = 10;

  printf("Extracting layer: %s (%d) ", layer_names[layer - min_layer], layer);
  tmp = LINK->boxes[layer - min_layer];
  while (tmp != NULL) {
    WITH = tmp;
    c--;
    if (c <= 0) {
      putchar('.');
      c = 10;
    }
    add_box(layer, WITH->llx * 2 + 1, WITH->lly * 2 + 1, WITH->urx * 2 + 1,
	    WITH->ury * 2 + 1);
	/* ***KLUGE*** */
    tmpnext = WITH->next;   /*tmp^.*/
    free(tmp);
    tmp = tmpnext;
  }
  printf("Memory left = %ld\n\n", asm_memavail());
}

Local void do_xtr_wire(node *tp, struct LOC_do_xtr *LINK)
{
  long tmp;
  box_rec *newnode;

  tr_4(tp->ll.x, tp->ll.y, tp->ur.x, tp->ur.y);

  if (tr_bx < tr_ax) {
    tmp = tr_bx;
    tr_bx = tr_ax;
    tr_ax = tmp;
  }
  if (tr_by < tr_ay) {
    tmp = tr_by;
    tr_by = tr_ay;
    tr_ay = tmp;
  }
  newnode = new_box();
  newnode->llx = tr_ax;
  newnode->lly = tr_ay;
  newnode->urx = tr_bx;
  newnode->ury = tr_by;
  newnode->next = NULL;
  /*writeln ('adding box to list');*/
  /*add_to_list (boxes, newnode);*/
  add_to_list(&LINK->new_boxes[tp->layer - min_layer], newnode);
  LINK->number_of_boxes++;
}

Local void do_xtr_geom_2(node *t_p, struct LOC_do_xtr *LINK)
{
  node *WITH;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DO_XTR_GEOM_2", false);
    goto _L1;
  }

  while (t_p != NULL) {
    WITH = t_p;
    if (t_p->layer != bb)   /*t_p^.*/
      do_xtr_wire(t_p, LINK);

    /*$if false$  { don't know what we should do with ports }
           ports := {t_p^.}portlist;
           if (ports <> NIL) and display_ports then
             begin
               while ports <> NIL do
                 begin
                    a := transform_point(ports^.p1);    { XFORM }
                    b := transform_point(ports^.p2);

                    set_layer(ports^.layerno);

                    m_move(a.x, a.y);
                    m_draw(b.x, b.y);

                    ports := ports^.next;
                 end;
              end;
         $end$*/

    if (WITH->child != NULL)   /*t_p^.*/
      do_xtr_geom_2(WITH->child, LINK);
    t_p = WITH->next;   /*t_p^.*/
  }
_L1: ;
}

Local void do_xtr_geom(node *t_p, struct LOC_do_xtr *LINK)
{
  long i;

  for (i = min_layer; i <= max_layer; i++)
    LINK->new_boxes[i - min_layer] = NULL;
  do_xtr_geom_2(t_p, LINK);
  preappend(LINK->new_boxes, LINK->boxes, LINK);   /* add to current list */
}

Local void do_xtr_box(long l, long x1, long y1, long x2, long y2,
		      struct LOC_do_xtr *LINK)
{
  long tmp;
  box_rec *newnode;

  tr_4(x1, y1, x2, y2);
  if (tr_bx < tr_ax) {
    tmp = tr_bx;
    tr_bx = tr_ax;
    tr_ax = tmp;
  }
  if (tr_by < tr_ay) {
    tmp = tr_by;
    tr_by = tr_ay;
    tr_ay = tmp;
  }

  newnode = new_box();
  newnode->llx = tr_ax;
  newnode->lly = tr_ay;
  newnode->urx = tr_bx;
  newnode->ury = tr_by;
  newnode->next = NULL;
  /*writeln('Adding routing box to list.');*/
  add_to_list(&LINK->new_boxes[l - min_layer], newnode);
  LINK->number_of_boxes++;
}

Local void do_xtr_routing(routing *pt, struct LOC_do_xtr *LINK)
{
  routing *to_pt;
  long w, i;
  routing *WITH;

  for (i = min_layer; i <= max_layer; i++)
    LINK->new_boxes[i - min_layer] = NULL;
  while (pt != NULL) {
    to_pt = pt;
    while (to_pt != NULL) {
      WITH = to_pt;
      w = WITH->width / 2;   /*to_pt^.*/
      if (WITH->pt1.x == WITH->pt2.x) {   /* vertical */
	if (WITH->pt1.y > WITH->pt2.y)
	  do_xtr_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y + w,
		     WITH->pt1.x + WITH->width - w, WITH->pt2.y - w, LINK);
	else
	  do_xtr_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y - w,
		     WITH->pt1.x + WITH->width - w, WITH->pt2.y + w, LINK);
      } else if (WITH->pt1.y == WITH->pt2.y) {
	if (WITH->pt1.x > WITH->pt2.x)
	  do_xtr_box(WITH->layer, WITH->pt1.x + w, WITH->pt1.y - w,
		     WITH->pt2.x - w, WITH->pt1.y + WITH->width - w, LINK);
	else
	  do_xtr_box(WITH->layer, WITH->pt1.x - w, WITH->pt1.y - w,
		     WITH->pt2.x + w, WITH->pt1.y + WITH->width - w, LINK);
      } else {
	printf("Can't do non-manhattan routing @ (%ld,%ld)\n",
	       WITH->pt1.x, WITH->pt1.y);
	if (do_output)
	  fprintf(ntk_out, "| Missing non-manhattan routing @ (%ld,%ld) ;\n",
		  WITH->pt1.x, WITH->pt1.y);
      }
      to_pt = to_pt->to_point;
    }
    pt = pt->next;
  }

  preappend(LINK->new_boxes, LINK->boxes, LINK);   /* add to current list */

  /* horizontal */
}

Local void do_xtr_comp_2(c_cell *root, struct LOC_do_xtr *LINK)
{
  tr_matrix old_matrix;

  old_matrix = tr_ctm;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in DO_XTR_COMP_2", false);
    return;
  }
  TRY(try6);
    while (root != NULL) {
      pl_tran(root->ll.x, root->ll.y);
      pl_xform(root->xform);

      if (root->tag == COMP) {
	do_xtr_routing(root->UU.U1.c_d->routing_, LINK);
	do_xtr_comp_2(root->UU.U1.c_d->data, LINK);
      } else
	do_xtr_geom(root->UU.g_d->data, LINK);

      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 do_xtr_comp_2", false);
      _Escape(10);
    }
  ENDTRY(try6);
}


Static void do_xtr(void)
{  /* find COMP MBB, and infer grid from that */
  struct LOC_do_xtr V;
  long i;
  tr_matrix old_mat;
  long start;
  Char out_name[fidleng + 1];   /* Name of NTK file */
  Char STR1[86];
  Char STR3[81];

  alpha_screen(CLR);
  m_alpha_on();
  m_graphics_off();
  strcpy(src_name, curr_comp_cell);

/* p2c: wol_xtract.text, line 2802:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_xtract.text, line 2802:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("\nUse \213-ABORT\200\210 for no output file.\n");
  sprintf(STR1, "%s.ntk", src_name);
  getfilename(out_name, "Name of output .ntk file? ", STR1);
  m_graphics_off();
  m_alpha_on();
  putchar('\n');
  if (*out_name == '\0' || strpos2(out_name, "-ABORT", 1) != 0)
    do_output = false;
  else {
    newci_fixfname(out_name, "ntk", "");
    printf("Output to \"%s\"\n", out_name);
    if (ntk_out != NULL)
      ntk_out = freopen(out_name, "w", ntk_out);
    else
      ntk_out = fopen(out_name, "w");
    if (ntk_out == NULL)
      _EscIO(FileNotFound);

    fprintf(ntk_out, "| WolExtract of \"%s\" on %s ;\n",
	    src_name, get_date_string(STR3));
    fprintf(ntk_out, "|    all coordinates are in Lambda. ;\n");
    do_output = true;
  }

  V.number_of_boxes = 0;
  for (i = min_layer; i <= max_layer; i++)
    V.boxes[i - min_layer] = NULL;

  printf("Sorting/flattening data structure.\n");

  start = timers_sysclock();
  old_mat = tr_ctm;   /* Save it for later */
  pl_ident();   /* make identity matrix */

  do_xtr_routing(comp_cells->routing_, &V);
  do_xtr_comp_2(comp_cells->data, &V);

  tr_ctm = old_mat;
  woltoxtrtime = timers_sysclock() - start;

  printf("Data structure flattened.  Memory left = %ld\n", asm_memavail());
  printf("Extracting layer by layer (one dot equals 10 boxes).\n");
  start = timers_sysclock();
  slurp(layer_poly, &V);
  slurp(layer_poly2, &V);
  slurp(layer_well, &V);
  slurp(layer_metal, &V);
  slurp(layer_sel, &V);
  slurp(layer_glass, &V);
  slurp(layer_metal2, &V);

  slurp(layer_via, &V);
  slurp(layer_cutp, &V);
  slurp(layer_diff, &V);
  slurp(layer_cuta, &V);
  slurp(layer_cut2, &V);
  xtrtime = timers_sysclock() - start;

  /*$if false$
   draw_boxes;
   writeln ('Press ENTER to continue');
   readln (s);  {pause for user response }
$end$*/

  start = timers_sysclock();
  find_transistors();
  trantime = timers_sysclock() - start;

  /*$if false$
   draw_boxes;
   writeln ('Press ENTER to continue');
   readln (s);  {pause for user response }
$end$*/

  show_stats();
  /* fix up all boxes from 2*+1 kluge */
  fix_this_shit();
  /*  draw_boxes;  */
  /*Don't want xtractor to display node numbers anymore*/
  if (do_output) {
    dump_nodes();
    fprintf(ntk_out, "| Boxes processed: %ld ;\n", V.number_of_boxes);
    fprintf(ntk_out, ".\n");
    if (ntk_out != NULL)
      fclose(ntk_out);
    ntk_out = NULL;
  } else
    mashnodes();
  equivforce();
  printf("%d N-transistors, %d P-transistors, ", numntran, numptran);
  printf("%d N2-transistors, %d P2-transistors, ", numntran2, numptran2);
      /***/
  printf("%ld total nodes (%ld orphans)\n",
	 total_nodes + orphan_nodes, orphan_nodes);
  printf("Number of boxes processed = %ld\n", V.number_of_boxes);
  m_graphics_on();
}


/*32*/

#define min_size        100   /* Minimum x or y size of a bin */
#define max_bins        256   /* Maximum number of bins in x or y */


Local void fixit(long size, long *bnum, long *bsize)
{
  if (size <= min_size) {
    *bnum = 1;
    *bsize = min_size;
  } else if (size < min_size * max_bins) {
    *bsize = min_size;
    *bnum = size / min_size + 1;
  } else {
    *bsize = size / max_bins + 1;
    *bnum = max_bins;
  }
  if (*bsize * *bnum < size)
    printf("\007Holy disappearing Lambda, Batman!\n");
}


void xtractor(void)
{
  long vsize, hsize;

  if (in_extract)
    xtr_free_mem();

  in_extract = true;
  set_c_bb(comp_cells);

  vsize = comp_cells->ur.y - comp_cells->ll.y + 2;   /* slop */
  fixit(vsize * 2 + 1, &biny, &binheight);   /****KLUGE****/
  hsize = comp_cells->ur.x - comp_cells->ll.x + 2;   /* slop */
  fixit(hsize * 2 + 1, &binx, &binwidth);   /****KLUGE****/

  re_init_mem();
  TRY(try7);
    do_xtr();

  RECOVER(try7);
    if (P_escapecode != -2 && P_escapecode != -20) {
      show_error("somewhere in do_xtr", false);
      printf("escapecode = %d\n", P_escapecode);
      _Escape(P_escapecode);
    }
    xtr_free_mem();
    in_extract = false;
  ENDTRY(try7);
}

#undef min_size
#undef max_bins




/* End. */
