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


/* Change these for testing */



#include "global.h"


#define WOL_CMD_G
#include "wol_cmd.h"


void bitch_bitch_bitch(Char *fname)
{
  /* simple gripe system */
  Char ch;
  FILE *gripefile;
  Char s[81];
  Char STR1[162];
  Char STR2[81];
  Char *TEMP;

  gripefile = NULL;
  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  ch = 'f';
  while (ch != 'X' && ch != 'x') {
    printf("\n\213          WOL  GRIPE  SYSTEM\210\n\n");
/* p2c: wol_cmd.text, line 196: Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 196:
 * Note: WRITE statement contains color/attribute characters [203] */
    printf(
      "Enter \"e\" to enter a gripe, \"r\" to read the gripe file, \"x\" to exit:  ");
/*    ch = getchar();*/
    ch = nk_getkey();
    if (ch == '\n')
      ch = ' ';
    putchar('\n');
    switch (ch) {

    case 'x':
    case 'X':   /* exit */
      break;

    case 'r':
    case 'R':   /* read gripe file */
      sprintf(STR1, "%s%s", WolLib, fname);
      read_motd_file(STR1);
      break;

    case 'e':
    case 'E':  /* add a gripe */
      TRY(try1);
	if (gripefile != NULL) {
	  sprintf(STR1, "%s%s", WolLib, fname);
	  gripefile = freopen(STR1, "a", gripefile);
	} else {
	  sprintf(STR1, "%s%s", WolLib, fname);
	  gripefile = fopen(STR1, "a");
	}
	if (gripefile == NULL) {
	  P_escapecode = -10;
	  P_ioresult = FileNotFound;
	  goto _Ltry1;
	}
	printf("Enter gripe, followed by blank line to terminate:\n");
	fprintf(gripefile, "WOL GRIPE by:  %s on %s\n",
		wol_username, get_date_string(STR2));
	do {
	  fgets(s, 81, stdin);
	  TEMP = strchr(s, '\n');
	  if (TEMP != NULL)
	    *TEMP = 0;
	  fprintf(gripefile, "  %s\n", s);
	} while (*s != '\0');
	if (gripefile != NULL)
	  fclose(gripefile);
	gripefile = NULL;
      RECOVER2(try1,_Ltry1);
	show_error("GRIPE: ", false);
	TRY(try2);
	  if (gripefile != NULL)
	    fclose(gripefile);
	  gripefile = NULL;   /* try to save it */
	RECOVER(try2);
	  ;
	ENDTRY(try2);
      ENDTRY(try1);
      /* if the file does not exist,  this will BOMB */
      break;

    default:
      printf("Unrecognized command: %c\n", ch);
      break;
    }
  }
  m_alpha_off();
  m_graphics_on();
  alpha_screen(CLR);
  if (gripefile != NULL)
    fclose(gripefile);
}


/* return */

#define max_zoom        32.0
#define min_zoom        0.01


void zoom_in_out(void)
{
  Char ans[81];
  long p;
  double new_zoom, old_zoom;
  boolean ok, done;
  tablet_info pen_data;
  point pen_point;
  Char *STR2;
  Char *TEMP;

  m_graphics_on();
  alpha_screen(CLR);
  m_alpha_on();
  old_zoom = zoom;

  do {
    printf("\nNew zoom factor [");
    if (intzoom)
      printf("%0.0f", old_zoom);
    else
      printf("%0.2f", old_zoom);
    printf("] (or draw RBB)? ");
    done = false;
    while (!done) {
      if (nk_keybufsize() != 0) {
	done = true;
	fgets(ans, 81, stdin);
	TEMP = strchr(ans, '\n');
	if (TEMP != NULL)
	  *TEMP = 0;
      }
      pen_data = get_pen();
      if (pen_data.depressed) {
	m_nocursor();
	done = true;
	window_zoom(true);
	*ans = '\0';
      } else {
	pen_point = scale_up(scale_down(change_to_point(pen_data.x, pen_data.y)));
	m_cursor(pen_point.x, pen_point.y);   /* emulate tracking */
      }
    }
    if (*ans == '\0') {
      m_graphics_on();
      m_alpha_off();
      goto _L1;   /* return */
    }

    TRY(try3);
      new_zoom = strtod(ans, &STR2);
      p = STR2 - ans + 1;
      ok = (new_zoom <= max_zoom && new_zoom >= min_zoom);
      if (!ok)
	printf("Zoom must be between %0.4f and %0.0f\n", min_zoom, max_zoom);

    RECOVER(try3);
      if (P_escapecode != -10)
	_Escape(P_escapecode);
      ok = false;
    ENDTRY(try3);
  } while (!ok);
  zoom_it(new_zoom);
_L1: ;
}

#undef max_zoom
#undef min_zoom


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

void undel_obj(void)
{
  short count;
  node *n;

  n = del_nodes[0];   /* Get the last deleted object */
  for (count = 1; count <= 4; count++)
	/* Move the undeleted objects up one in array */
	  del_nodes[count - 1] = del_nodes[count];
  del_nodes[4] = NULL;   /* Clear out the last node     */
  reshuffle(n);   /* Put all deleted nodes back into tree.   */
  refresh_geom();   /* Show them                   */
}


Local void capture(node *last_added, point ll, point ur, node *tree,
		   long nest)
{
  node *scan, *scannext;

  scan = tree;
  while (scan != NULL) {
    scannext = scan->next;
    if (scan->ll.x >= ll.x && scan->ll.y >= ll.y && scan->ur.x <= ur.x &&
	scan->ur.y <= ur.y && scan->layer != sel_box)
    {  /* object is totally contained, so slurp it */
      /* writeln (' ':nest, 'found contained object: layer = ',scan^.layer:0); */
      node_out_of_tree(scan);
      scan->next = last_added->child;
      scan->parent = last_added;
      last_added->child = scan;
    } else {
      if (scan->ur.x > ll.x && scan->ur.y > ll.y && scan->ll.x < ur.x &&
	  scan->ll.y < ur.y && scan->layer != sel_box)
      {  /* there must be some intersection */
	/* writeln (' ': nest, 'found partial object: layer = ',scan^.layer:0); */
	capture(last_added, ll, ur, scan->child, nest + 3);
      }
      /*else writeln (' ': nest, 'skipped over object:  layer = ',scan^.layer:0) */
    }
    scan = scannext;
  }
}


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

/* Add a select box to the structure.  Return true if the select box was */
/* really added. */
/* This is an attempt to let the select box grab everything it can */
boolean start_select(point start)
{
  point ll, ur;

  ll = scale_up(start);
  set_layer(sel_box);
  last_added = NULL;
  if (get_rbb(&ll, &ur)) {
    add_wire(ll, ur, sel_box, "", NULL);
    capture(last_added, ll, ur, main_, 1);
  }
  return (last_added != NULL && last_added->layer == sel_box);
}


#define threshold       12   /* put in config file ??? */


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

Static void debounce_mode(point start, Char *mode)
{
  tablet_info new_pt;

  if (strcmp(mode, "ALL")) {   /* just do usual thing */
    /*debounce();*/
    return;
  }
  new_pt = get_pen();   /* get current position */
  if (labs(new_pt.x - start.x) + labs(new_pt.y - start.y) > threshold)
    strcpy(mode, "SEL");

  /* wait for pen to be lifted;  if it is > 4 pixels away, do SEL mode */
}

#undef threshold


void delete_obj(point start, short modenum, Char *mode_)
{
  Char mode[8];
  node *obj;
  short count;

  strcpy(mode, mode_);
  debounce_mode(start, mode);
  /* debounce;  old way */
  start = scale_down(start);
  if (!strcmp(mode, "SEL")) {   /* Get the object.                   */
    if (start_select(start))
      obj = last_added;
    else
      obj = NULL;
  } else
    obj = parent_of(main_, start, start, 1);
  if (obj == NULL)   /* If one was selected...    */
    return;
  node_out_of_tree(obj);   /* Clear node from tree.     */
  if (!strcmp(mode, "ONE"))   /* If only one item is to be */
  {  /* deleted...            */
    reshuffle(obj->child);   /* Put its children back into tree */
    obj->child = NULL;   /* and clear node's children   */
  }
  recl_nodes(&del_nodes[4]);   /* Put end of delete into garbage */
  for (count = 0; count <= 3; count++)   /* Shuffle the del array back one */
    del_nodes[4 - count] = del_nodes[3 - count];
  del_nodes[0] = obj;   /* Put node (and children sometimes */
  /* onto del array           */
  modify(GEOM);
  if (auto_refresh) {   /* Show the changes         */
    refresh_geom();
    return;
  }

  make_matrix();
  small_graphics();
  gstate.ref_in_black = true;
  redisplay(obj);
  gstate.ref_in_black = false;
  make_matrix();
}


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

void edit_obj(point start)
{
  node *obj;
  short side_to_edit;
  tablet_info t_p, old_pen;
  point t_pp, original_ll, original_ur;

  /*debounce();*/
  old_pen.x = start.x;
  old_pen.y = start.y;   /* initial position */
  start = scale_down(start);
  obj = parent_of(main_, start, start, 1);
  if (obj == NULL)
    return;
  original_ll = obj->ll;
  original_ur = obj->ur;
  if (start.x == obj->ll.x)
    side_to_edit = 1;
  else if (start.y == obj->ur.y)
    side_to_edit = 2;
  else if (start.x == obj->ur.x) {
    if (start.y == obj->ll.y)
      side_to_edit = 4;
    else
      side_to_edit = 3;
  } else if (start.y == obj->ll.y)
    side_to_edit = 4;
  else
    side_to_edit = 0;
  if (side_to_edit <= 0)
    return;
  m_nocursor();
  xor_on();
  do {
    t_p = check_pen();
    if (t_p.x != old_pen.x || t_p.y != old_pen.y) {
      old_pen = t_p;
      t_pp = scale_down(change_to_point(t_p.x, t_p.y));
      set_layer(obj->layer);
      draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
      switch (side_to_edit) {

      case 1:
	obj->ll.x = t_pp.x;
	break;

      case 2:
	obj->ur.y = t_pp.y;
	break;

      case 3:
	obj->ur.x = t_pp.x;
	break;

      case 4:
	obj->ll.y = t_pp.y;
	break;
      }
      draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
    }
  } while (!t_p.depressed && t_p.near_);
  if (!t_p.near_) {
    /* erase last object drawn */
    draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
    /* restore original sizes */
    obj->ll = original_ll;
    obj->ur = original_ur;
    /* draw object */
    draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
  }
  xor_off();
  node_out_of_tree(obj);
  reshuffle(obj);
  if (auto_refresh)
    refresh_geom();
  modify(GEOM);
}


Local long corners_match(point start, node *obj)
{
  /* returns 1 if ll.x, ll.x match start
            2 if ll.x, ur.y
            3 if ur.x, ur.y
            4 if ur.x, ll.y
            0 otherwise
   */
  if (obj->ll.x == start.x && obj->ll.y == start.y)
    return 1;
  else if (obj->ll.x == start.x && obj->ur.y == start.y)
    return 2;
  else if (obj->ur.x == start.x && obj->ur.y == start.y)
    return 3;
  else if (obj->ur.x == start.x && obj->ll.y == start.y)
    return 4;
  else
    return 0;
}


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

void move_obj(point start, short modenum, Char *mode_)
{
  Char mode[8];
  node *obj, *obj_parent;
  tablet_info pen_position, t_p, old_pen;
  point original_ll, original_ur, t_pp;
  long corner_to_edit;
  boolean move_select_mode;

  strcpy(mode, mode_);
  TRY(try4);
    debounce_mode(start, mode);
    start = scale_down(start);
    move_select_mode = false;
    if (!strcmp(mode, "SEL")) {
      if (start_select(start)) {
	move_select_mode = true;
	obj = last_added;
	last_moved = NULL;
	/*debounce();*/
	pen_position = check_pen();
	start = scale_down(change_to_point(pen_position.x, pen_position.y));
      } else
	obj = NULL;
      /* Pretend to push the MOVE button again */
      /* I.e., change to ALL mode. */
      /* menu_press(menu_find_item(menu_curr,'MOVE'));
           do not do this any more -- due to auto-reinstate */

    } else
      obj = parent_of(main_, start, start, 1);
    if (obj != NULL) {
      corner_to_edit = corners_match(start, obj);
      if (corner_to_edit != 0 && !move_select_mode && obj->layer != sel_box) {
	if (last_moved != NULL && last_moved != obj) {
	  if (parent_of(last_moved, start, start, 1) != NULL) {
	    printf("deep inside 1\n");
	    reinstate();
	    obj = parent_of(main_, start, start, 1);
	  } else
	    reinstate();
	} else if (last_moved == obj) {
	  printf("deep inside 2\n");
	  reinstate();
	  obj = parent_of(main_, start, start, 1);
	}
	obj_parent = obj->parent;
	node_out_of_tree(obj);
	obj->next = NULL;
	reshuffle(obj->child);   /* put contents back in tree */
	obj->child = NULL;
	/* now edit the corner */
	old_pen.x = scale_up(start).x;
	old_pen.y = scale_up(start).y;
	m_nocursor();
	original_ll = obj->ll;
	original_ur = obj->ur;
	xor_on();
	do {
	  t_p = check_pen();
	  if (t_p.x != old_pen.x || t_p.y != old_pen.y) {
	    old_pen = t_p;
	    t_pp = scale_down(change_to_point(t_p.x, t_p.y));
	    set_layer(obj->layer);
	    draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
	    switch (corner_to_edit) {

	    case 1:
	      obj->ll.x = t_pp.x;
	      obj->ll.y = t_pp.y;
	      break;

	    case 2:
	      obj->ll.x = t_pp.x;
	      obj->ur.y = t_pp.y;
	      break;

	    case 3:
	      obj->ur.x = t_pp.x;
	      obj->ur.y = t_pp.y;
	      break;

	    case 4:
	      obj->ur.x = t_pp.x;
	      obj->ll.y = t_pp.y;
	      break;
	    }
	    draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
	  }
	} while (!t_p.depressed && t_p.near_);
	if (!t_p.near_) {
	  /* erase last object drawn */
	  draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
	  /* restore original sizes */
	  obj->ll = original_ll;
	  obj->ur = original_ur;
	  /* draw object */
	  draw_rbb(scale_up(obj->ll), scale_up(obj->ur));
	}
	xor_off();
	reshuffle(obj);
	modify(GEOM);
	if (auto_refresh)
	  refresh_geom();
      } else {  /* do a real MOVE */
	first_dotted = (last_moved == obj);
	if (last_moved != obj && last_moved != NULL) {
	  printf("deep inside 3\n");
	  reinstate();
	  obj = parent_of(main_, start, start, 1);
	}
	last_moved = obj;
	obj_parent = obj->parent;
	node_out_of_tree(obj);
	if (!strcmp(mode, "ONE")) {   /* Deal with only one object.  */
	  obj->next = NULL;   /* No next pointer anymore     */
	  reshuffle(obj->child);   /* Children stay in tree       */
	  obj->child = NULL;   /* No children anymore.        */
	}
	move_a_tree(obj, start);   /* Move the point around       */
	/*$if false$ { currently must reinstate immediately }
                   if auto_refresh then refresh_geom;
                   small_graphics;
                   gstate.dotted := true;
                   redisplay(obj);
                   gstate.dotted := false;
                   big_graphics;
                   if mode = 'SEL' then menu_show;
                   restore_in_tree(obj);
                   modify(GEOM);
                   $end$*/
	restore_in_tree(obj);   /* fix this someday ... */
	reinstate();   /* automatically refreshes */
	modify(GEOM);

      }
    }
  RECOVER(try4);
    if (P_escapecode == 10)
      _Escape(10);
    else {
      show_error("ERROR in procedure MOVE_OBJ", false);
      _Escape(10);
    }
  ENDTRY(try4);
}


/*******************************************************************************/
void erase_names(node *obj)
{
  while (obj != NULL) {
    *obj->name = '\0';
    erase_names(obj->child);
    obj = obj->next;
  }
}


void copy_obj(point start, short modenum, Char *mode_)
{
  Char mode[8];
  node *obj, *obj_parent;
  point start_loc, offset, orig_offset, orig_ll;
  tablet_info pen_position;

  strcpy(mode, mode_);
  debounce_mode(start, mode);
  /* debounce;    old way */
  start = scale_down(start);
  if (!strcmp(mode, "SEL")) {
    if (start_select(start)) {
      obj = last_added;
      last_moved = NULL;
      /*debounce();*/
      pen_position = check_pen();
      start = scale_down(change_to_point(pen_position.x, pen_position.y));
    } else
      obj = NULL;
  } else
    obj = parent_of(main_, start, start, 1);
  if (obj == NULL)
    return;
  /* last_moved := obj;   */
  last_moved = NULL;
  obj_parent = obj->parent;
  node_out_of_tree(obj);
  obj->next = NULL;
  retain_nodes = true;
  reshuffle(obj);   /* put the original back in NOW */
  if (!strcmp(mode, "ONE")) {
    recl_nodes(&obj->child);   /* We eat our children       */
    obj->child = NULL;   /* No children anymore.      */
  }
  erase_names(obj);
  /* we are now ready to insert this copy everywhere */
  retain_nodes = true;
  orig_ll = obj->ll;
  orig_offset = change_to_point(obj->ll.x - start.x, obj->ll.y - start.y);
  small_graphics();   /* MAS - prevent menu trash */
  if (!point_to_point_move)
    xor_on();
  if (!point_to_point_move)
    redisplay(obj);
  do {
    start_loc = obj->ll;
    move_a_tree(obj, start);   /* Move the point around       */
    offset.x = start_loc.x - obj->ll.x;
    offset.y = start_loc.y - obj->ll.y;
    /*refresh_geom;*/
    /*writeln ('x and y offsets: ',offset.x, offset.y);*/
    if (offset.x != 0 || offset.y != 0) {
      modify(GEOM);
      /* gstate.dotted := true;       */
      gstate.dotted = false;
      small_graphics();
      xor_off();
      /*debounce();*/   /* make sure the pen is UP */
      redisplay(obj);
      xor_on();
      if (!point_to_point_move)
	redisplay(obj);
      big_graphics();
      gstate.dotted = false;
      reshuffle(obj);
    }
    /* do nothing */
    start.x = obj->ll.x - orig_offset.x;
    start.y = obj->ll.y - orig_offset.y;
  } while (get_pen().near_);
  retain_nodes = false;   /* for future */
  recl_nodes(&obj);   /* eat the last instance */
  last_moved = NULL;   /* nuke this for re-instate */
  if (auto_refresh)
    refresh_geom();
}


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

/* Simple routine to indicate that the main buffers have been modified */
void modify(cell_typ buff)
{
  if (buff == GEOM)
    geom_cells->modified = true;
  else
    comp_cells->modified = true;
}


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

void clear_main(void)
{
  boolean go_ahead;

  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  go_ahead = true;
  if (geom_cells->modified)
    go_ahead = yes_no_quest("Are you sure you want to clear the main buffer");
  if (go_ahead) {
    *curr_geom_cell = '\0';   /* Forget cell name now */
    recl_nodes(&main_);
    geom_cells->data = NULL;
    geom_cells->modified = false;
    main_ = NULL;
    refresh_geom();
  }
  m_graphics_on();
}


/*******************************************************************************/
void get_elecnode(point start)
{
  node *obj;
  Char newname[11];
  Char *TEMP;

  /*debounce();*/   /* Get the pen up.                   */
  start = scale_down(start);
  obj = parent_of(main_, start, start, 1);
      /* Get the object.                   */
  if (obj == NULL)   /* If one was selected...            */
    return;
  modify(GEOM);
  xor_on();
  gstate.dotted = true;
  set_layer(obj->layer);
  draw_wire(obj->ll, obj->ur);
  alpha_screen(CLR);
  m_alpha_on();
  putchar('\n');
  if (*obj->name == '\0')
    printf("Enter node name: ");
  else
    printf("Enter new node name [%s]:  ", obj->name);
  fgets(newname, 11, stdin);
  TEMP = strchr(newname, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  if (*newname != '\0') {
    if (strpos2(newname, ".", 1) == 0)
      strcpy(obj->name, newname);
    else {
      if (strlen(newname) > 1)
	printf("WARNING:  illegal period (.) found in name: %s\n", newname);
      printf("Old name [%s] deleted\n", obj->name);
      *obj->name = '\0';
    }
  }
  xor_off();
  gstate.dotted = false;
  reset_layer();
  draw_wire(obj->ll, obj->ur);
}


/* Local variables for mirror: */
struct LOC_mirror {
  Char mir;
  long x0, y0;
} ;

/* Local variables for mirr: */
struct LOC_mirr {
  struct LOC_mirror *LINK;
} ;

Local void xfrm(node *p, struct LOC_mirr *LINK)
{
  node sh;

  sh = *p;
  switch (LINK->LINK->mir) {

  case 'X':
  case 'x':
    sh.ur.x = LINK->LINK->x0 - p->ll.x;
    sh.ll.x = LINK->LINK->x0 - p->ur.x;
    break;

  case 'Y':
  case 'y':
    sh.ur.y = LINK->LINK->y0 - p->ll.y;
    sh.ll.y = LINK->LINK->y0 - p->ur.y;
    break;
  }/*case*/
  *p = sh;
}  /*xfrm*/

Local void mirr(node *p, struct LOC_mirror *LINK)
{
  struct LOC_mirr V;

  V.LINK = LINK;
  xfrm(p, &V);
  p = p->child;
  while (p != NULL) {
    mirr(p, LINK);
    p = p->next;
  }
}  /*mirr*/

Local void mirror(node *p, Char mir_)
{
  struct LOC_mirror V;

  V.mir = mir_;
  if (p == NULL)
    return;
  V.x0 = p->ur.x + p->ll.x;
  V.y0 = p->ur.y + p->ll.y;
  mirr(p, &V);
}  /*mirror*/

/* Local variables for rotate: */
struct LOC_rotate {
  short rot, x0, y0, y1;
} ;

/* Local variables for rotr: */
struct LOC_rotr {
  struct LOC_rotate *LINK;
} ;

Local void xfrm_(node *p, struct LOC_rotr *LINK)
{
  node sh;

  sh = *p;
  if (LINK->LINK->rot == 90) {
    sh.ll.x = LINK->LINK->x0 + LINK->LINK->y1 - p->ur.y;
    sh.ur.x = LINK->LINK->x0 + LINK->LINK->y1 - p->ll.y;
    sh.ll.y = LINK->LINK->y0 - LINK->LINK->x0 + p->ll.x;
    sh.ur.y = LINK->LINK->y0 - LINK->LINK->x0 + p->ur.x;
  } else if (LINK->LINK->rot == 180) {
    sh.ur.x = LINK->LINK->x0 - p->ll.x;
    sh.ll.x = LINK->LINK->x0 - p->ur.x;
    sh.ur.y = LINK->LINK->y0 - p->ll.y;
    sh.ll.y = LINK->LINK->y0 - p->ur.y;
  }
  *p = sh;
}  /*xfrm*/

Local void rotr(node *p, struct LOC_rotate *LINK)
{
  struct LOC_rotr V;

  V.LINK = LINK;
  xfrm_(p, &V);
  p = p->child;
  while (p != NULL) {
    rotr(p, LINK);
    p = p->next;
  }  /*while ...*/
}  /*rotr*/

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

Local void rotate(node *p, short rot_)
{
  struct LOC_rotate V;
  short x1;

  V.rot = rot_;
  if (p == NULL)
    return;
  if (V.rot == 180) {
    V.x0 = p->ur.x + p->ll.x;
    V.y0 = p->ur.y + p->ll.y;
  } else if (V.rot == 90) {
    V.x0 = p->ll.x;
    x1 = p->ur.x;
    V.y0 = p->ll.y;
    V.y1 = p->ur.y;
  }
  rotr(p, &V);
}  /*rotate*/




void xform_geom(point start, short modenum, Char *modename)
{
  node *obj, *obj_parent;


  TRY(try5);
    /*debounce();*/
    start = scale_down(start);
    obj = parent_of(main_, start, start, 1);
    if (obj != NULL) {
      modify(GEOM);
      first_dotted = (last_moved == obj);
      if (last_moved != obj && last_moved != NULL) {
	reinstate();
	obj = parent_of(main_, start, start, 1);
      }
      obj_parent = obj->parent;
      node_out_of_tree(obj);

      switch (modenum) {

      case 0:
	rotate(obj, 90);
	break;

      case 1:
	rotate(obj, 180);
	break;

      case 2:
	mirror(obj, 'x');
	break;

      case 3:
	mirror(obj, 'y');
	break;
      }

      gstate.dotted = false;   /*####Does this one work? */
      restore_in_tree(obj);
      if (last_moved != NULL)
	reinstate();
      refresh_geom();
    }
  RECOVER(try5);
    if (P_escapecode == 10)
      _Escape(10);
    else {
      show_error("procedure XFORM_GEOM", false);
      _Escape(10);
    }
  ENDTRY(try5);
}


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

void stretch_geom(void)
{
  printf("PROCEDURE stretch_geom called\n");
}


void define_port(point start)
{
  node *obj;
  port_node *p;
  Char *TEMP;

  printf("PROCEDURE define_port called\n");
  start = scale_down(start);
  obj = parent_of(main_, start, start, 1);   /* Get the object.     */
  if (obj == NULL)
    return;
  modify(GEOM);
  p = get_port_node();
  xor_on();   /* hilight the geometry piece */
  gstate.dotted = true;
  set_layer(obj->layer);
  draw_wire(obj->ll, obj->ur);
  alpha_screen(CLR);
  m_alpha_on();
  printf("\nEnter port name: ");
  fgets(p->name, 11, stdin);
  TEMP = strchr(p->name, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  if (*p->name != '\0') {
    printf("Enter port type: ");
    fgets(p->signaltype, 81, stdin);
    TEMP = strchr(p->signaltype, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    printf("Enter port orientation: (NSEW) ");
/*    p->side = getchar();*/
    p->side = nk_getkey();
    if (p->side == '\n')
      p->side = ' ';
    putchar('\n');
    switch (p->side) {

    case 'n':
    case 'N':
      p->side = 'N';
      p->p1.x = obj->ll.x;
      p->p2.x = obj->ur.x;
      p->p1.y = obj->ur.y;
      p->p2.y = obj->ur.y;
      break;

    case 's':
    case 'S':
      p->side = 'S';
      p->p1.x = obj->ll.x;
      p->p2.x = obj->ur.x;
      p->p1.y = obj->ll.y;
      p->p2.y = obj->ll.y;
      break;

    case 'e':
    case 'E':
      p->side = 'E';
      p->p1.x = obj->ur.x;
      p->p2.x = obj->ur.x;
      p->p1.y = obj->ll.y;
      p->p2.y = obj->ur.y;
      break;

    default:
      if (p->side != 'W' && p->side != 'w')
	printf("WARNING:  WEST side assumed\n");
      p->side = 'W';
      p->p1.x = obj->ll.x;
      p->p2.x = obj->ll.x;
      p->p1.y = obj->ll.y;
      p->p2.y = obj->ur.y;
      break;
    }/* case */
    sprintf(p->layer, "%.*s",
	    (int)(strlen(layers[obj->layer - min_layer].cif_name) - 1),
	    layers[obj->layer - min_layer].cif_name + 1);
    p->layerno = obj->layer;
    p->width = 0;   /* for now */
    /* now insert in list of ports of that object */
    p->next = obj->portlist;
    obj->portlist = p;
  } else
    recl_port_nodes(&p);
  xor_off();
  gstate.dotted = false;
  reset_layer();
  draw_wire(obj->ll, obj->ur);
}


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

/* if XFORM is >=0, then set up stuff to print it. */
void geom_line(cell *g, short xform)
{
  short s_len, spacing;

  if (xform >= 0) {
    /*  write(#140);     MAS -- always want GREEN geom cells */
    s_len = 25;
    spacing = 16;
  } else {
    s_len = 30;
    if (g->modified)
      printf("\213\201+\200\210");
    else
      printf("\215-\210");
/* p2c: wol_cmd.text, line 1084:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1084:
 * Note: WRITE statement contains color/attribute characters [203] */
    spacing = 21;
  }
  fputs(g->name, stdout);
  printf("%*s", s_len - strlen(g->name), "GEOM");
  if (g->ur.x == INFIN)
    printf("%*s", spacing + 1, "NONE");
  else
    printf("%*ld", spacing + 1, g->ur.x - g->ll.x);
  if (g->ur.y == INFIN)
    printf("%*s", spacing - 1, "NONE");
  else
    printf("%*ld", spacing - 1, g->ur.y - g->ll.y);
  if (xform >= 0)
    printf("%10d\n", xform);
  else
    putchar('\n');
/* p2c: wol_cmd.text, line 1099: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1099:
 * Note: WRITE statement contains color/attribute characters [203] */
  putchar(136);

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


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

/* if XFORM is >=0, then set up stuff to print it. */
void comp_line(comp_list *c, short xform)
{
  short s_len;

  if (xform >= 0) {
    putchar(140);
    s_len = 25;
  } else {
    s_len = 30;
    if (c->modified)
      printf("\213\201+\200\210");
    else
      printf("\215-\210");
/* p2c: wol_cmd.text, line 1119:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1119:
 * Note: WRITE statement contains color/attribute characters [203] */
  }
/* p2c: wol_cmd.text, line 1112: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1112:
 * Note: WRITE statement contains color/attribute characters [203] */
/* p2c: wol_cmd.text, line 1122: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1122:
 * Note: WRITE statement contains color/attribute characters [203] */
  putchar(140);   /* MAS -- always want BLUE comp cells */
  fputs(c->name, stdout);
  printf("%*s", s_len - strlen(c->name), "COMP");
  if (c->ur.x == INFIN)
    printf("%17s", "NONE");
  else
    printf("%17ld", c->ur.x - c->ll.x);
  if (c->ur.y == INFIN)
    printf("%15s", "NONE");
  else
    printf("%15ld", c->ur.y - c->ll.y);
  if (xform >= 0)
    printf("%10d\n", xform);
  else
    putchar('\n');
/* p2c: wol_cmd.text, line 1134: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1134:
 * Note: WRITE statement contains color/attribute characters [203] */
  putchar(136);

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


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

void list_cells(void)
{
  cell *scan;
  Char ch;
  boolean cont;
  short count;

  geom_cells->data = main_;
  set_bb(geom_cells);
  scan = geom_cells;
  m_graphics_off();
  m_alpha_on();
  cont = true;
  while (cont) {
    alpha_screen(CLR);
    printf("Cell name%24s%20s%20s\n\n", "Cell Type", "Width", "Height");
    count = 0;
    do {
      geom_line(scan, -1);
      scan = scan->next;
      count++;
    } while (scan != geom_cells && count < 19);
    printf("\n\nPress pen or any key to continue (EXECUTE to quit): ");
    ch = wait_pen_or_kbd();
    if (scan == geom_cells || ch == '\003')
      cont = false;
  }
  alpha_screen(CLR);
  m_graphics_on();
  m_alpha_off();
}


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

void get_ports(node *pt, port_node **list)
{
  /* pt points to tree from which a linear port list will be extracted */
  /* list points to the head of the returned list */
  port_node *port2, *port3;

  if (pt == NULL)
    return;
  get_ports(pt->next, list);
  port2 = pt->portlist;
  while (port2 != NULL) {
    port3 = get_port_node();
    *port3 = *port2;
    port3->next = *list;
    *list = port3;
    port2 = port2->next;
  }
  get_ports(pt->child, list);
}


Static void simple_do_check_pen(tablet_info *check_pen)
{
  tablet_info t_i;

  gsave();
  xor_off();
  t_i = get_pen();
  *check_pen = t_i;   /* return tablet info, as required */
}


void make_cell(void)
{
  tablet_info t_p;
  Char t_name[81];
  node *obj;
  cell *scan;
  comp_list *o_sc;
  cell *t_cell;
  point start;
  boolean ok_make;   /* Ok to make the cell? */
  boolean ok_over;   /* is it OK to overwrite the cell ? */
  boolean drawn_mbb;   /* did the user draw the mbb himself ? */
  _PROCEDURE old_do_check_pen;
  Char ch;

  geom_cells->data = main_;
  m_nocursor();
  ok_over = false;
  ok_make = true;
  drawn_mbb = false;
  alpha_screen(CLR);
  getgeomcellname(t_name, "What is the name of the cell? ", curr_geom_cell);

  if (strcmp(t_name, "*GEOM*") && strpos2("-ABORT", t_name, 1) == 0) {
    if (!strcmp(t_name, curr_geom_cell))   /* update name */
      ok_over = true;
    else
      strcpy(curr_geom_cell, t_name);
    /* look for that name in composition cell name list */
    o_sc = comp_cells;
    do {
      o_sc = o_sc->next;
    } while (o_sc != comp_cells && strcmp(o_sc->name, t_name));
    if (o_sc != comp_cells)
      show_message("That name is already used by a composition cell.", true);
    else {
      /* look for that cell name in the geometry cell list */
      scan = geom_cells;
      do {
	scan = scan->next;
      } while (strcmp(scan->name, t_name) && scan != geom_cells);
      if (scan != geom_cells) {
	if (ok_over)
	  ok_make = true;
	else
	  ok_make = yes_no_quest("Cell already exists.  OK to overwrite");
	if (ok_make) {
	  scan->prev->next = scan->next;
	  scan->next->prev = scan->prev;
	  recl_nodes(&scan->data);
	  recl_g_cell(&scan);   /* erase old cell from table */
	  scan = geom_cells;   /* point to head of list for insertion */
	}
      }
      if (ok_make) {
	show_message("Press and key or buton MBB, otherwise draw bounding box.",
		     true);
	old_do_check_pen = check_pen_proc;
	TRY(try6);
	  check_pen_proc.proc = simple_do_check_pen;
	  check_pen_proc.link = NULL;

	  big_graphics();
	  /*debounce();*/
	  t_p = check_pen();
	  while (!t_p.depressed && nk_keybufsize() == 0) {
	    t_p = check_pen();
	    if (t_p.y > TOP_OF_SCREEN && t_p.x > END_OF_MENU)
	      t_p.y = TOP_OF_SCREEN;
	    if (t_p.y <= TOP_OF_SCREEN)
	      t_p = scale(t_p, 3);
	    if (cursor_on)
	      m_cursor(t_p.x, t_p.y);
	  }
	  if (t_p.depressed) {
	    /*debounce();*/   /* Get the pen up again */
	    if (t_p.y <= TOP_OF_SCREEN + 3)
	      t_p.menu = 0;
	    else
	      t_p.menu = 11;
	    m_nocursor();
		/* GEG  if the calling routine wants it, it will put it back */
	  } else {
/*	    ch = getchar();*/
	      ch = nk_getkey();
	    if (ch == '\n')
	      ch = ' ';
	    t_p.menu = 1;
	  }

	  check_pen_proc = old_do_check_pen;

	RECOVER(try6);
	  check_pen_proc = old_do_check_pen;
	ENDTRY(try6);
	/*$if false$
                    show_message('Press MAKE again for MBB, otherwise select LL and UR of BB',true);
                    t_p := track;
$end$*/
	if (t_p.menu > 0)   /*  ****** FIX ME ****** */
	  obj = main_;
	else {
	  start.x = t_p.x;
	  start.y = t_p.y;
	  set_layer(bb);
	  make_wire(start, bb);
	  if (last_added->layer != bb)
	    obj = NULL;
	  else {
	    drawn_mbb = true;
	    obj = last_added;
	  }
	}
	/* menu square pushed */
	m_alpha_off();   /* clear prompt off screen */
	alpha_screen(CLR);
	if (obj != NULL) {
	  if (scan == geom_cells) {   /* insert at head of list */
	    /* writeln (#140'Inserting at head of list'#136);  */
	    t_cell = get_g_cell();
	    strcpy(t_cell->name, t_name);
	    t_cell->next = geom_cells->next;
	    t_cell->prev = geom_cells;
	    geom_cells->next = t_cell;
	    t_cell->next->prev = t_cell;
	    scan = t_cell;
	  }

	  if (drawn_mbb) {  /* object must already have an MBB */
	    node_out_of_tree(obj);
	    fast_shuf(obj);   /* copy the whole object */
	    scan->data = obj;
	    scan->data->next = NULL;   /*count only things INSIDE MBB */
	    set_bb(scan);   /* must always find size of MBB */
	    scan->data = obj->child;   /* do not copy MBB */
	  } else {  /* mbb not drawn, so obj must equal main */
	    scan->data = main_;
	    set_bb(scan);   /* must always find size of MBB */
	    if (obj->layer != bb || obj->next != NULL) {  /*must add an MBB */
	      add_wire(scan->ll, scan->ur, bb, "", NULL);
	      obj = last_added;
	    }
	    node_out_of_tree(obj);
	    fast_shuf(obj);   /* copy the whole object */
	    scan->data = obj->child;   /* do not copy MBB */
	  }
	  obj->child = NULL;
	  obj->next = NULL;
	  recl_nodes(&obj);   /* clean things up a little */

	  inc_nodes(scan->data, -scan->ll.x, -scan->ll.y);
	  /* adjust port list as well */

	  /* build up port list for geom cell */
	  scan->portlist = NULL;
	  get_ports(scan->data, &scan->portlist);

	  scan->ur.x -= scan->ll.x;
	  scan->ur.y -= scan->ll.y;
	  scan->ll.x = 0;
	  scan->ll.y = 0;
	  scan->modified = true;   /* just gotten from main buffer */
	  strcpy(scan->revision_date, geom_cells->revision_date);
	  scan->revision_number = geom_cells->revision_number;
	  geom_cells->modified = false;
	}
      }
      if (!strcmp(current_buffer_name, "GEOM"))
	refresh_geom();
    }
  }
  update_comp_mbb();
}


/*******************************************************************************/
void immediate_make_cell(void)
{
  /* this will make the GEOM buffer into the cell named by curr_geom_cell.
     It will select the largest MBB possible, and will overwrite without
     confirmation from the user.  It is intended primarily to be used
     as part of the called_from_comp mechanism.
  */
  Char t_name[81];
  node *obj;
  cell *scan, *t_cell;

  geom_cells->data = main_;
  m_nocursor();
  alpha_screen(CLR);
  strcpy(t_name, curr_geom_cell);

  if (strcmp(t_name, "*GEOM*") && *t_name != '\0') {
    /* look for that cell name in the geometry cell list */
    scan = geom_cells;
    do {
      scan = scan->next;
    } while (strcmp(scan->name, t_name) && scan != geom_cells);
    if (scan != geom_cells) {
      scan->prev->next = scan->next;
      scan->next->prev = scan->prev;
      recl_nodes(&scan->data);
      recl_g_cell(&scan);   /* erase old cell from table */
      scan = geom_cells;   /* point to head of list for insertion */
    }
    obj = main_;
    if (obj != NULL) {
      if (scan == geom_cells) {   /* insert at head of list */
	/* writeln (#140'Inserting at head of list'#136);  */
	t_cell = get_g_cell();
	strcpy(t_cell->name, t_name);
	t_cell->next = geom_cells->next;
	t_cell->prev = geom_cells;
	geom_cells->next = t_cell;
	t_cell->next->prev = t_cell;
	scan = t_cell;
      }

      scan->data = main_;
      set_bb(scan);   /* must always find size of MBB */
      if (obj->layer != bb || obj->next != NULL) {  /*must add an MBB */
	add_wire(scan->ll, scan->ur, bb, "", NULL);
	obj = last_added;
      }
      node_out_of_tree(obj);
      fast_shuf(obj);   /* copy the whole object */
      scan->data = obj->child;   /* do not copy MBB */

      obj->child = NULL;
      obj->next = NULL;
      recl_nodes(&obj);   /* clean things up a little */

      inc_nodes(scan->data, -scan->ll.x, -scan->ll.y);
      /* adjust port list as well */

      /* build up port list for geom cell */
      scan->portlist = NULL;
      get_ports(scan->data, &scan->portlist);

      scan->ur.x -= scan->ll.x;
      scan->ur.y -= scan->ll.y;
      scan->ll.x = 0;
      scan->ll.y = 0;
      scan->modified = true;   /* just gotten from main buffer */
      strcpy(scan->revision_date, geom_cells->revision_date);
      scan->revision_number = geom_cells->revision_number;
      geom_cells->modified = false;
    }
    if (!strcmp(current_buffer_name, "GEOM"))
      refresh_geom();
  }
  update_comp_mbb();
}


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

void new_main_cell(void)
{
  /* return early */
  Char new_cell[81];
  cell *scan;
  Char STR2[100];

  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  if (main_ != NULL) {
    if (geom_cells->modified) {
      if (!yes_no_quest("There is data in the main cell.  OK to destroy")) {
	m_graphics_on();
	goto _L1;   /* return */
      }
    }
    recl_nodes(&main_);
    main_ = NULL;
    *curr_geom_cell = '\0';   /* Forget cell name now.  GEG */
    geom_cells->revision_number = -1;   /* forget these too */
    *geom_cells->revision_date = '\0';
    geom_cells->modified = false;
  }

  alpha_screen(CLR);
  getgeomcellname(new_cell, "Name of cell to move to main? ", "");
  if (*new_cell == '\0' || strpos2("-ABORT", new_cell, 1) != 0) {
    m_graphics_on();
    refresh_geom();
    goto _L1;   /* return */
  }
  scan = geom_cells;
  do {
    scan = scan->next;
  } while (scan != geom_cells && strcmp(scan->name, new_cell));
  if (scan == geom_cells) {
    sprintf(STR2, "Cell: %s not found.", new_cell);
    show_message(STR2, false);
  } else {
    strcpy(curr_geom_cell, new_cell);
    geom_cells->revision_number = scan->revision_number;
    strcpy(geom_cells->revision_date, scan->revision_date);
    /* add_wire(scan^.ll,scan^.ur,BB,'',nil); */
    fast_shuf(scan->data);
    add_wire(scan->ll, scan->ur, bb, "", NULL);
	/* MBB goes outside -- MAS */

    zoom = (long)(0.9 * ((double)RIGHT_OF_SCREEN / scan->ur.x));
    if ((long)(0.9 * ((double)TOP_OF_SCREEN / scan->ur.y)) < zoom)
      zoom = (long)(0.9 * ((double)TOP_OF_SCREEN / scan->ur.y));
    if (zoom < 1.0)   /* convert to "integer" */
      zoom = 1.0;
    else
      zoom = (long)zoom;
    izoom = (long)zoom;
    intzoom = (zoom == izoom);

    off_x = -(long)((RIGHT_OF_SCREEN / zoom - scan->ur.x) / 2);
    off_y = -(long)((TOP_OF_SCREEN / zoom - scan->ur.y) / 2);
  }

  m_graphics_on();
  refresh_geom();
_L1: ;
}


/*******************************************************************************/
void immediate_new_main_cell(Char *new_cell_)
{
  /* loads a new geometry cell into the GEOM buffer, with a minimum of
     user prompting;  Intended to be called from COMP buffer */
  Char new_cell[81];
  /* return early */
  cell *scan;
  Char STR1[122];

  strcpy(new_cell, new_cell_);
  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  if (main_ != NULL) {
    if (geom_cells->modified) {
      if (!yes_no_quest("There is data in the main cell.  OK to destroy")) {
	m_graphics_on();
	goto _L1;   /* return */
      }
    }
    recl_nodes(&main_);
    main_ = NULL;
    *curr_geom_cell = '\0';   /* Forget cell name now.  GEG */
    geom_cells->revision_number = -1;   /* forget these too */
    *geom_cells->revision_date = '\0';
    geom_cells->modified = false;
  }

  /* new_cell := getgeomcellname(#L'Name of cell to move to main? ','');  */
  if (*new_cell == '\0') {
    m_graphics_on();
    refresh_geom();
/* p2c: wol_cmd.text, line 1573:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 1573:
 * Note: WRITE statement contains color/attribute characters [203] */
    printf("\213THIS SHOULD NEVER HAPPEN:  IMMEDIATE_NEW_MAIN_CELL\210\n");
    goto _L1;   /* return */
  }
  scan = geom_cells;
  do {
    scan = scan->next;
  } while (scan != geom_cells && strcmp(scan->name, new_cell));
  if (scan == geom_cells) {
    sprintf(STR1, "Cell: %s not found (not a geometry cell).", new_cell);
    show_message(STR1, false);
  } else {
    strcpy(curr_geom_cell, new_cell);
    geom_cells->revision_number = scan->revision_number;
    strcpy(geom_cells->revision_date, scan->revision_date);
    /* add_wire(scan^.ll,scan^.ur,BB,'',nil); */
    fast_shuf(scan->data);
    add_wire(scan->ll, scan->ur, bb, "", NULL);
	/* MBB goes outside -- MAS */

    zoom = (long)(0.9 * ((double)RIGHT_OF_SCREEN / scan->ur.x));
    if ((long)(0.9 * ((double)TOP_OF_SCREEN / scan->ur.y)) < zoom)
      zoom = (long)(0.9 * ((double)TOP_OF_SCREEN / scan->ur.y));
    if (zoom < 1.0)   /* convert to "integer" */
      zoom = 1.0;
    else
      zoom = (long)zoom;
    izoom = (long)zoom;
    intzoom = (zoom == izoom);

    off_x = -(long)((RIGHT_OF_SCREEN / zoom - scan->ur.x) / 2);
    off_y = -(long)((TOP_OF_SCREEN / zoom - scan->ur.y) / 2);
  }

  m_graphics_on();
  /* refresh_geom;   done by entry into BUILD menu */
_L1: ;
}


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

void append_cell(void)
{
  Char app_cell[81];
  cell *scan;
  tablet_info t_p;
  point new_pt, t1, t2;
  Char STR2[100];

  /*debounce();*/
  m_nocursor();
  alpha_screen(CLR);
  getgeomcellname(app_cell, "Name of cell to append? ", "");
  if (strpos2("-ABORT", app_cell, 1) != 0)   /* abort now!! */
    goto _L1;
  if (*app_cell == '\0')
    goto _L1;
  scan = geom_cells;
  do {
    scan = scan->next;
  } while (strcmp(scan->name, app_cell) && scan != geom_cells);
  if (scan != geom_cells) {
    show_message("Depress pen on lower left point for cell addition.", true);
    t_p = track();
    m_alpha_off();
    if (t_p.menu == 0) {
      new_pt = scale_down(change_to_point(t_p.x, t_p.y));
      new_pt.x -= scan->ll.x;
      new_pt.y -= scan->ll.y;
      inc_nodes(scan->data, new_pt.x, new_pt.y);
      t1 = scan->ll;
      t1.x += new_pt.x;
      t1.y += new_pt.y;
      t2 = scan->ur;
      t2.x += new_pt.x;
      t2.y += new_pt.y;
      /* add_wire(t1,t2,BB,'',nil); MAS -- used to be here */
      retain_nodes = true;
      reshuffle(scan->data);
      retain_nodes = false;
      add_wire(t1, t2, bb, "", NULL);
      inc_nodes(scan->data, -new_pt.x, -new_pt.y);
      refresh_geom();
      modify(GEOM);   /* mark GEOM modified */
    }
  } else {
    sprintf(STR2, "Cell \"%s\" not found.", app_cell);
    show_message(STR2, true);
  }
_L1: ;
}


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

Char *check_for_used(Char *Result, Char *s)
{
  comp_list *t_sc;
  c_cell *t_cc;
  boolean fl;
  Char t_n[81];

  t_sc = comp_cells;
  do {
    t_sc = t_sc->next;
    t_cc = t_sc->data;
    fl = false;
    if (t_cc != NULL) {
      do {
	switch (t_cc->tag) {

	case GEOM:
	  strcpy(t_n, t_cc->UU.g_d->name);
	  break;

	case COMP:
	  strcpy(t_n, t_cc->UU.U1.c_d->name);
	  break;
	}
	if (!strcmp(t_n, s))
	  fl = true;
	else
	  t_cc = t_cc->next;
      } while (t_cc != NULL && fl != true);
    }
  } while (t_sc != comp_cells && fl != true);
  if (fl == true)
    return strcpy(Result, t_sc->name);
  else
    return strcpy(Result, "");
}


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

void delete_cell(void)
{
  Char del_cell[81];
  cell *scan;
  Char used[81];
  Char STR1[200];
  Char STR3[100];

  /*debounce();*/
  m_nocursor();
  alpha_screen(CLR);
  getgeomcellname(del_cell, "Name of cell to erase? ", "");
  if (strpos2("-ABORT", del_cell, 1) != 0)   /* abort now!! */
    goto _L1;
  if (*del_cell == '\0')
    goto _L1;
  scan = geom_cells;
  do {
    scan = scan->next;
  } while (strcmp(scan->name, del_cell) && scan != geom_cells);
  if (scan != geom_cells) {
    check_for_used(used, del_cell);
    if (*used != '\0') {
      sprintf(STR1, "Cannot delete %s.  It is called by cell %s",
	      del_cell, used);
      show_message(STR1, true);
    } else {
      scan->prev->next = scan->next;
      scan->next->prev = scan->prev;
      recl_nodes(&scan->data);
      recl_g_cell(&scan);
    }
  } else {
    sprintf(STR3, "Cell \"%s\" not found.", del_cell);
    show_message(STR3, true);
  }
_L1: ;
}


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

/* default setup for WOL plotting routines */
boolean plot_setup(void)
{
  boolean doit;
  Char ch;

  doit = yes_no_quest("Plotter ready");
  if (!doit)
    return doit;
  pl_init();
  if (!strcmp(pl_id, "7475A") || !strcmp(pl_id, "7585B"))
    return doit;
  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  printf("\nFull, Half, or Default paper? ");
  do {
    ch = nk_getkey();
    if (islower(ch))
      ch -= 32;
    if (ch != '\015' && ch != ' ' && ch != 'D' && ch != 'F' && ch != 'H')
      printf(" H,F,D or space\007\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  } while (ch != '\015' && ch != ' ' && ch != 'D' && ch != 'F' && ch != 'H');
  putchar('\n');
  m_graphics_on();
  m_alpha_off();
  if (ch == 'F')
    pl_setsize(100, 500, 15000, 10500);
  else if (ch == 'H')
    pl_setsize(100, 500, 10500, 7500);
  return doit;
}


/* cleanup the HPIB, etc. after an error in a plotting routine */
/* does not print error messages */
void plot_cleanup(void)
{
  tablet_reset();   /* clear tablet */
  P_writestring(705, ";IN;");   /* clear plotter*/
}


Local void plotlyr(node *p, short layer)
{
  /* traverses data structure, and plots all boxes of colour 'layer' */
  while (p != NULL) {
    if (p->layer == layer)
      pl_box(p->ll.x, p->ll.y, p->ur.x, p->ur.y);
    plotlyr(p->child, layer);
    p = p->next;
  }
}


void plot(void)
{
  /* plots the contents of *GEOM* on a HP pen plotter */
  long layer, n;
  cell *bb, *scan;
  node *p;
  Char message[81];
  long llx, lly, urx, ury;
  plotter_disp_info *WITH;
  Char STR2[81];

  TRY(try7);
    if (plot_setup()) {
      /* find *GEOM* buffer */
      scan = geom_cells;

      while (strcmp(scan->name, "*GEOM*") && scan != NULL)
	    /* look for *GEOM* */
	      scan = scan->next;
      if (scan == NULL) {
	show_message("This should never happen in PLOT", true);
	P_escapecode = 10;
	goto _Ltry7;
      }

      /* this should never happen*/
      p = main_;

      /* initialize plot window */
      bb = get_g_cell();
      *bb = *scan;
      bb->data = main_;
      set_bb(bb);
      pl_scaleto(bb->ll.x, bb->ll.y, bb->ur.x, bb->ur.y, true);

      for (layer = min_layer; layer <= max_layer; layer++) {
	WITH = &layers[layer - min_layer].plot;
	if (WITH->color != 0) {   /* this layer has a pen */
	  pl_color(WITH->color);
	  /* should do something about linestyles... */
	  plotlyr(p, layer);
	}  /* for */
      }

      /* write cell name, size, and date */
      sprintf(message, "%ld x %ld LAMBDA    %s",
	      bb->ur.x - bb->ll.x, bb->ur.y - bb->ll.y,
	      get_date_string(STR2));
      n = strlen(message) + 1;
      pl_scaleoff();
      pl_getsize(&llx, &lly, &urx, &ury);
      pl_move(llx + 10, lly + 50);
      pl_text(message);
      pl_end();
    }
  RECOVER2(try7,_Ltry7);
    show_error("procedure: PLOT", false);
    printf("Plotting geometry cell: %s\n", scan->name);
    plot_cleanup();
    waitfor(300);
    m_graphics_on();
    m_alpha_off();
  ENDTRY(try7);
}


/* Local variables for list_comp_cells: */
struct LOC_list_comp_cells {
  short count;
} ;

Local void header(struct LOC_list_comp_cells *LINK)
{
  alpha_screen(CLR);
  printf("Cell name%24s%15s%15s%10s\n\n",
	 "Cell Type", "Width", "Height", "Xform");
  LINK->count = 0;
}

Local void trailer(struct LOC_list_comp_cells *LINK)
{
  Char c;

  printf("\n\nPress pen or any key to continue (EXECUTE to quit): ");
  c = wait_pen_or_kbd();
  if (c == '\003')
    _Escape(13);
}


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

void list_comp_cells(void)
{
  struct LOC_list_comp_cells V;
  comp_list *scan;
  boolean cont;
  c_cell *o_sc;

  m_graphics_off();
  m_alpha_on();
  scan = comp_cells;
  cont = true;
  set_c_bb(comp_cells);
  TRY(try8);
    while (cont) {
      header(&V);
      do {
	comp_line(scan, -1);
	o_sc = scan->data;
	while (o_sc != NULL) {
	  if (V.count == 18) {
	    trailer(&V);
	    header(&V);
	  }
	  printf("      ");
	  if (o_sc->tag == GEOM)
	    geom_line(o_sc->UU.g_d, o_sc->xform);
	  else
	    comp_line(o_sc->UU.U1.c_d, o_sc->xform);
	  V.count++;
	  o_sc = o_sc->next;
	}
	scan = scan->next;
	V.count++;
      } while (scan != comp_cells && V.count < 19);
      trailer(&V);
      if (scan == comp_cells)
	cont = false;
    }
  RECOVER(try8);
    if (P_escapecode != 13) {
      show_error("list_comp_cells", false);
      _Escape(10);
    }
  ENDTRY(try8);
  alpha_screen(CLR);
  m_graphics_on();
  m_alpha_off();
}


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

void add_comp_cell(void)
{
  Char t_ans[81];
  cell *t_p;
  comp_list *t_op;
  boolean t_f;   /* true if adding geom cell; false if comp */
  boolean cell_found;
  tablet_info t_pp;
  point new_point;
  c_cell *t_a_p;
  Char STR2[100];

  /*debounce();*/
  m_nocursor();
  alpha_screen(CLR);
  getcellname(t_ans, "Name of cell to add? ", "");
  if (strpos2("-ABORT", t_ans, 1) != 0)   /* abort now!! */
    goto _L1;
  if (*t_ans == '\0')
    goto _L1;
  t_f = true;
  cell_found = false;
  t_p = geom_cells;
  do {
    t_p = t_p->next;
  } while (t_p != geom_cells && strcmp(t_p->name, t_ans));
  if (t_p == geom_cells) {
    t_f = false;
    t_op = comp_cells;
    do {
      t_op = t_op->next;
    } while (t_op != comp_cells && strcmp(t_op->name, t_ans));
    if (t_op != comp_cells)
      cell_found = true;
  } else
    cell_found = true;
  if (cell_found == true) {
    show_message("Depress pen on lower left point for cell addition.", true);
    do {
      t_pp = track();
    } while (t_pp.menu != 0);
    m_alpha_off();
    new_point = scale_down(change_to_point(t_pp.x, t_pp.y));
    t_a_p = get_c_c_cell();
    t_a_p->next = comp_cells->data;
    comp_cells->data = t_a_p;
    comp_cells->data->ll = new_point;
    comp_cells->data->xform = 0;
    if (t_f == true) {
      comp_cells->data->tag = GEOM;
      comp_cells->data->ur = change_to_point(
	  t_p->ur.x - t_p->ll.x + comp_cells->data->ll.x,
	  t_p->ur.y - t_p->ll.y + comp_cells->data->ll.y);
      comp_cells->data->UU.g_d = t_p;
      comp_cells->data->prefixid = get_new_prefixid(comp_cells->data->UU.g_d->
						    name, "GEOM");
    } else {
      comp_cells->data->tag = COMP;
      comp_cells->data->ur = change_to_point(
	  t_op->ur.x - t_op->ll.x + comp_cells->data->ll.x,
	  t_op->ur.y - t_op->ll.y + comp_cells->data->ll.y);
      comp_cells->data->UU.U1.c_d = t_op;
      comp_cells->data->prefixid = get_new_prefixid(
	  comp_cells->data->UU.U1.c_d->name, "COMP");
      comp_cells->data->UU.U1.old_c_d = t_op;
    }
    modify(COMP);
    show_comp();
  } else {
    sprintf(STR2, "Cell: \"%s\" not found.", t_ans);
    show_message(STR2, true);
  }
_L1: ;
}


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

c_cell *which_comp(comp_list *c, point p)
{
  /* Function returns */
  /* which subcell of c contains pen point p    */
  c_cell *Result, *t_sc, *select_scan;
  boolean cont;
  /*t_oc           :     c_cell; */
  point ll, ur;

  if (edges_only && !select_in_progress_c) {
    find_all_possible_objects(p);
    if (select_list_head_c != NULL)
      return (select_list_head_c->select_list);
    edges_only = false;
    t_sc = which_comp(c, p);
    Result = t_sc;
    edges_only = true;
    return Result;
  } else {
    if (select_in_progress_c && select_list_head_c != NULL) {
      Result = last_selected_object_c->select_list;
      unhighlight_c(last_selected_object_c);
      select_scan = select_list_head_c;
      while (select_list_head_c != NULL) {
	select_scan = select_list_head_c->next;
	recl_c_c_cell(&select_list_head_c);
	select_list_head_c = select_scan;
      }
      last_selected_object_c = NULL;
      select_in_progress_c = false;
      return Result;
    } else {
      t_sc = c->data;
      /* p := scale_up(p); good guess. */
      cont = true;
      while (cont == true) {
	if (t_sc == NULL) {
	  cont = false;
	  break;
	}
	xform_node(t_sc, &ll, &ur);
	/*t_oc := xform_node(t_sc^);*/
	if (p.x >= ll.x && p.x <= ur.x && p.y >= ll.y && p.y <= ur.y)
	  cont = false;
	else
	  t_sc = t_sc->next;
      }
      return t_sc;
    }
  }
  return Result;
}


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

boolean move_a_comp(c_cell *m_obj, point start)
{
  /* returns true if operation completed successfully, false otherwise */
  tablet_info new_pen;
  point new_pt, delta;
  /*t_oc   : c_cell;*/
  point ll, ur;
  boolean completed_ok;

  xor_on();
  completed_ok = true;
  gstate.dotted = true;
  set_layer(comp_box);   /*####Weirdness */
  xform_node(m_obj, &ll, &ur);
  ll = scale_up(ll);
  ur = scale_up(ur);
  draw_rbb(ll, ur);

  /*t_oc := xform_node(m_obj^);*/
  /*draw_rbb(t_oc.ll,t_oc.ur);*/
  do {
    new_pen = check_pen();
    new_pt = scale_down(change_to_point(new_pen.x, new_pen.y));
    delta.x = new_pt.x - start.x;
    delta.y = new_pt.y - start.y;
    if (delta.x != 0 || delta.y != 0) {
      /*t_oc := xform_node(m_obj^);*/
      /*draw_rbb(t_oc.ll,t_oc.ur);*/
      xform_node(m_obj, &ll, &ur);
      ll = scale_up(ll);
      ur = scale_up(ur);
      draw_rbb(ll, ur);
      m_obj->ll.x += delta.x;
      m_obj->ll.y += delta.y;
      m_obj->ur.x += delta.x;
      m_obj->ur.y += delta.y;
      /*t_oc := xform_node(m_obj^);*/
      /*draw_rbb(t_oc.ll,t_oc.ur);*/
      xform_node(m_obj, &ll, &ur);
      ll = scale_up(ll);
      ur = scale_up(ur);
      draw_rbb(ll, ur);
      start = new_pt;
    }
  } while (!new_pen.depressed && new_pen.near_);
  if (!new_pen.near_)
    completed_ok = false;
  xor_off();
  gstate.dotted = false;
  return completed_ok;
}


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

void move_comp(point start)
{
  c_cell *m_obj, m_obj_cell, *t_sc;
  point old_ll, old_ur;

  /*debounce();*/
  start = scale_down(start);
  m_obj = which_comp(comp_cells, start);
  if (m_obj == NULL)
    return;
  if (comp_cells->data == m_obj)
    comp_cells->data = m_obj->next;
  else {
    t_sc = comp_cells->data;
    while (t_sc->next != m_obj)
      t_sc = t_sc->next;
    t_sc->next = m_obj->next;
  }
  if (auto_refresh)
    show_comp();
  else {
    make_matrix();
    small_graphics();
    bb_state = bb_clip;
    /* create a copy in case user shift-stops while refreshing */
    m_obj_cell = *m_obj;
    /* nil out children to fake-out show_comp_2 */
    m_obj_cell.next = NULL;
    /* erase the object */
    gstate.ref_in_black = true;
    show_comp_2(&m_obj_cell);
    gstate.ref_in_black = false;
    make_matrix();
  }
  modify(COMP);
  old_ll = m_obj->ll;
  old_ur = m_obj->ur;
  if (move_a_comp(m_obj, start)) {  /* insert new box */
    m_obj->next = comp_cells->data;
    comp_cells->data = m_obj;
    if (auto_refresh)
      show_comp();
    return;
  }
  m_obj->ur = old_ur;
  m_obj->ll = old_ll;
  m_obj->next = comp_cells->data;
  comp_cells->data = m_obj;
  if (auto_refresh)
    show_comp();

  /* restore to old position */
}


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

void array_comp(void)
{
  /* asks for two comp cells to be selected.  Calculates offset from LL to LL.
     asks for replication factor (n).  Then generates (n-2) of cell B.
  */
  c_cell *cell1, *cell2, *new_obj;
  long replication, i;
  tablet_info new_pen;
  point new_pt, true_ll1, true_ur1, true_ll2, true_ur2;
  long dx, dy;

  show_message("Select array basis (two comp cells): ", true);
  new_pen = track();
  new_pt = scale_down(change_to_point(new_pen.x, new_pen.y));
  cell1 = which_comp(comp_cells, new_pt);
  if (cell1 == NULL) {
    alpha_screen(CLR);
    return;
  }
  new_pen = track();
  new_pt = scale_down(change_to_point(new_pen.x, new_pen.y));
  cell2 = which_comp(comp_cells, new_pt);
  if (cell2 == NULL || cell1 == cell2)
    show_message("Two distinct cells required for array basis", false);
  else {
    /* find true ll corner of boxes -- after xform */
    xform_node(cell1, &true_ll1, &true_ur1);
    xform_node(cell2, &true_ll2, &true_ur2);
    dx = true_ll2.x - true_ll1.x;
    dy = true_ll2.y - true_ll1.y;
    new_pt = cell1->ll;
    new_pt.x += dx * 2;
    new_pt.y += dy * 2;
    alpha_screen(CLR);
    printf("\nEnter replication count: ");
    scanf("%ld%*[^\n]", &replication);
/*    getchar();*/
    nk_getkey();
    for (i = 3; i <= replication; i++) {
      new_obj = get_c_c_cell();
      *new_obj = *cell1;
      new_obj->ur.x -= new_obj->ll.x;   /* re-normalize */
      new_obj->ur.y -= new_obj->ll.y;
      *new_obj->prefix = '\0';
	  /* do not have multiple cells of same prefix */
      if (new_obj->tag == GEOM)
	new_obj->prefixid = get_new_prefixid(new_obj->UU.g_d->name, "GEOM");
      else
	new_obj->prefixid = get_new_prefixid(new_obj->UU.U1.c_d->name, "COMP");
      new_obj->ll.x = new_pt.x;
      new_obj->ll.y = new_pt.y;
      new_obj->ur.x += new_pt.x;
      new_obj->ur.y += new_pt.y;
      modify(COMP);
      new_obj->next = comp_cells->data;
      comp_cells->data = new_obj;
      new_pt.x += dx;   /* next position */
      new_pt.y += dy;
      m_alpha_off();
      alpha_screen(CLR);
    }
  }
  show_comp();
}


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

void undelete_comp(void)
{
  c_cell *t_op;

  if (comp_undelete_list == NULL)
    return;
  t_op = comp_undelete_list;
  comp_undelete_list = comp_undelete_list->next;
  t_op->next = comp_cells->data;
  comp_cells->data = t_op;

  modify(COMP);
  show_comp();
}


void del_comp(point start)
{
  c_cell *d_obj, *t_sc;
  long i;

  /*debounce();*/
  start = scale_down(start);
  d_obj = which_comp(comp_cells, start);
  if (d_obj == NULL)
    return;
  if (comp_cells->data == d_obj)
    comp_cells->data = d_obj->next;
  else {
    t_sc = comp_cells->data;
    while (t_sc->next != d_obj)
      t_sc = t_sc->next;
    t_sc->next = d_obj->next;
  }
  /* used to be: recl_c_c_cell(d_obj);  */
  /* instead, add it to the undelete stack */
  d_obj->next = comp_undelete_list;
  comp_undelete_list = d_obj;
  /* check to see if we have too many cells in undelete list*/
  i = 0;
  t_sc = comp_undelete_list;
  while (t_sc != NULL && i < 5) {
    t_sc = t_sc->next;
    i++;
  }
  if (t_sc != NULL) {
    /* need to reclaim routing cells here */
    recl_c_c_cell(&t_sc);
  }

  modify(COMP);
  show_comp();
}



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

void copy_comp(point start)
{
  c_cell *c_obj, *n_obj;

  /*debounce();*/
  start = scale_down(start);
  c_obj = which_comp(comp_cells, start);
  if (c_obj == NULL)
    return;
  m_color(BR_WHITE);
  n_obj = get_c_c_cell();
  *n_obj = *c_obj;
  *n_obj->prefix = '\0';   /* do not have multiple cells of same prefix */
  if (n_obj->tag == GEOM)
    n_obj->prefixid = get_new_prefixid(n_obj->UU.g_d->name, "GEOM");
  else
    n_obj->prefixid = get_new_prefixid(n_obj->UU.U1.c_d->name, "COMP");
  if (move_a_comp(n_obj, start)) {  /* copy OK, so insert */
    n_obj->next = comp_cells->data;
    comp_cells->data = n_obj;
    if (auto_refresh)
      show_comp();
  } else {  /* not a good copy, so eliminate */
    recl_c_c_cell(&n_obj);
    if (auto_refresh)
      show_comp();
  }
  modify(COMP);
}


/*******************************************************************************/
Static routing *dupl_tree(routing *rt)
{
  /* duplicates the tree pointed to by rt, and returns a pointer to it */
  routing *rt2;

  rt2 = NULL;
  if (rt == NULL)
    return rt2;
  rt2 = get_routing_node();
  *rt2 = *rt;
  rt2->to_point = dupl_tree(rt->to_point);
  rt2->next = dupl_tree(rt->next);
  return rt2;
}


Local void adjust_routing(routing *rt, long x0, long y0)
{
  /* offset all the wires in the tree by x0, y0 */
  if (rt == NULL)
    return;
  /* writeln (rt^.pt1.x,rt^.pt1.y,rt^.pt2.x,rt^.pt2.y );  */
  rt->pt1.x += x0;
  rt->pt1.y += y0;
  rt->pt2.x += x0;
  rt->pt2.y += y0;
  /* writeln ('updating to_point');  */
  adjust_routing(rt->to_point, x0, y0);
  /* writeln ('updating next');   */
  adjust_routing(rt->next, x0, y0);
}


void make_comp(void)
{
  comp_list *t_c, *t_oc;
  c_cell *t_cc, *t1_cc;
  cell *t_g;
  Char t_name[81];
  boolean ok_make;   /* Ok to make cell? */
  boolean ok_over;   /* is it OK to overwrite previous cell ? */

  /*debounce();*/
  m_nocursor();
  ok_make = true;
  alpha_screen(CLR);
  getcellname(t_name, "What is the name of the cell? ", curr_comp_cell);
  if (strpos2("-ABORT", t_name, 1) != 0)   /* abort now!! */
    goto _L1;
  ok_over = (strcmp(t_name, curr_comp_cell) == 0);
  strcpy(curr_comp_cell, t_name);

  t_g = geom_cells;
  do {
    t_g = t_g->next;
  } while (t_g != geom_cells && strcmp(t_g->name, t_name));
  if (!strcmp(t_g->name, t_name))
    show_message("That name is already used by a geometry cell.", true);
  else {
    t_c = comp_cells;
    do {
      t_c = t_c->next;
    } while (t_c != comp_cells && strcmp(t_c->name, t_name));
    if (!strcmp(t_name, t_c->name)) {
      if (!ok_over)
	ok_make = yes_no_quest("Cell already exists.  OK to overwrite");
      if (ok_make) {
	ok_over = true;
	t_oc = comp_cells;
	while (t_oc->next != t_c)
	  t_oc = t_oc->next;
	t_oc->next = t_c->next;
	/* return prefix ids of t_c to free list here */
	recl_c_cell(&t_c);
      }
    }
    if (ok_make) {
      set_c_bb(comp_cells);
      t_c = get_c_cell();
      *t_c = *comp_cells;
      t_c->modified = true;   /* Just got this from *COMP* */
      comp_cells->modified = false;   /* Just saved to new cell */
      strcpy(t_c->revision_date, comp_cells->revision_date);
      t_c->revision_number = comp_cells->revision_number;
      t_c->data = NULL;
      strcpy(t_c->name, t_name);
      t_cc = comp_cells->data;
      while (t_cc != NULL) {
	t1_cc = get_c_c_cell();
	*t1_cc = *t_cc;
	/* creating new cell */
	/* can not really get prefix for not-yet defined cell */
	/* get_new_prefixid (t1_cc^.name, 'COMP') */
	t1_cc->ur.x -= t_c->ll.x;
	t1_cc->ur.y -= t_c->ll.y;
	t1_cc->ll.x -= t_c->ll.x;
	t1_cc->ll.y -= t_c->ll.y;
	t1_cc->next = t_c->data;
	t_c->data = t1_cc;
	t_cc = t_cc->next;
      }

      t_c->routing_ = dupl_tree(comp_cells->routing_);
      adjust_routing(t_c->routing_, -t_c->ll.x, -t_c->ll.y);

      t_c->ur.x -= t_c->ll.x;
      t_c->ur.y -= t_c->ll.y;
      t_c->ll.x = 0;
      t_c->ll.y = 0;
      comp_cells->next = t_c;
      update_comp_mbb();
    }
  }
_L1: ;
}


Local void reclaim_routing(routing *rt)
{
  if (rt != NULL) {
    reclaim_routing(rt->next);
    recl_routing_node(&rt);
  }
}


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

void erase_comp(void)
{
  Char t_ans[81];
  comp_list *t_sc, *t_op;
  Char used[81];
  Char STR2[100];
  Char STR3[204];

  /*debounce();*/
  m_nocursor();
  alpha_screen(CLR);
  getcellname(t_ans, "Name of cell to erase? ", "");
  if (strpos2("-ABORT", t_ans, 1) != 0)   /* abort now!! */
    goto _L1;
  t_sc = comp_cells;
  while (t_sc->next != comp_cells && strcmp(t_sc->next->name, t_ans))
    t_sc = t_sc->next;
  if (t_sc->next == comp_cells) {
    sprintf(STR2, "Cell: \"%s\" not found.", t_ans);
    show_message(STR2, false);
  } else {
    check_for_used(used, t_ans);
    if (*used != '\0') {
      sprintf(STR3, "Cannot delete \"%s\".  It is called by cell \"%s\"",
	      t_ans, used);
      show_message(STR3, false);
    } else {
      t_op = t_sc->next;
      t_sc->next = t_op->next;
      reclaim_routing(t_op->routing_);
      recl_c_cell(&t_op);
    }
  }
_L1: ;
}


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

void clear_m_comp(void)
{
  c_cell *t_c, *t1_c;
  routing *rt, *oldrt;

  small_clear();
  t_c = comp_cells->data;
  while (t_c != NULL) {
    t1_c = t_c;
    t_c = t_c->next;
    recl_c_c_cell(&t1_c);
  }
  rt = comp_cells->routing_;
  while (rt != NULL) {
    oldrt = rt;
    rt = rt->next;
    recl_routing_node(&oldrt);
  }
  comp_cells->data = NULL;
  comp_cells->routing_ = NULL;
  comp_cells->modified = false;
  *curr_comp_cell = '\0';   /* forget the cell name we were editing */
}


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

boolean clear_comp(void)
{
  boolean doclear;

  doclear = true;
  m_nocursor();
  alpha_screen(CLR);
  if (comp_cells->modified) {   /* abort */
    if (!yes_no_quest("There is data in the main comp cell.  OK to destroy"))
      doclear = false;
  }
  if (doclear)
    clear_m_comp();
  return doclear;
}


/*******************************************************************************/
void new_comp_cell(void)
{
  c_cell *t_c, *t1_c;
  Char new_cell[81];
  comp_list *scan;
  Char STR2[100];

  /*debounce();*/
  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  set_c_bb(comp_cells);
  if (comp_cells->ur.x != INFIN) {
    if (!clear_comp())
      goto _L1;
  }

  alpha_screen(CLR);
  getcellname(new_cell, "Name of cell to move to main? ", "");
  if (strpos2("-ABORT", new_cell, 1) != 0)   /* abort now!! */
    goto _L1;
  if (*new_cell == '\0')
    goto _L1;
  scan = comp_cells;
  do {
    scan = scan->next;
  } while (scan != comp_cells && strcmp(scan->name, new_cell));
  if (scan == comp_cells) {
    sprintf(STR2, "Cell: \"%s\" not found.", new_cell);
    show_message(STR2, true);
  } else {
    strcpy(curr_comp_cell, new_cell);
    t_c = scan->data;
    comp_cells->routing_ = dupl_tree(scan->routing_);

    while (t_c != NULL) {
      t1_c = get_c_c_cell();
      *t1_c = *t_c;
      t1_c->next = comp_cells->data;
      comp_cells->data = t1_c;
      t_c = t_c->next;
    }
    set_c_bb(comp_cells);
    strcpy(comp_cells->revision_date, scan->revision_date);
    comp_cells->revision_number = scan->revision_number;
    comp_cells->modified = false;

    zoom = 0.8 * (RIGHT_OF_SCREEN / scan->ur.x);
    if (0.8 * (TOP_OF_SCREEN / scan->ur.y) < zoom)
      zoom = 0.8 * (TOP_OF_SCREEN / scan->ur.y);
    if (zoom < 1.0)   /* convert to "integer" */
      zoom = 1.0;
    else
      zoom = (long)zoom;
    izoom = (long)zoom;
    intzoom = (zoom == izoom);

    off_x = -(long)((RIGHT_OF_SCREEN / zoom - scan->ur.x) / 2);
    off_y = -(long)((TOP_OF_SCREEN / zoom - scan->ur.y) / 2);
  }
  m_graphics_on();
  show_comp();
_L1:
  m_graphics_on();
}


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

void xform_comp(point start, short xform, Char *modename)
{
  c_cell *w_o;
  long oldcx, oldcy, newcx, newcy;
  point ll, ur;

  /*debounce();*/
  start = scale_down(start);
  w_o = which_comp(comp_cells, start);
  if (w_o == NULL)
    return;
  xform_node(w_o, &ll, &ur);
  oldcx = (ll.x + ur.x) / 2;
  oldcy = (ll.y + ur.y) / 2;
  w_o->xform = xf[w_o->xform][xform];
  xform_node(w_o, &ll, &ur);
  newcx = (ll.x + ur.x) / 2;
  newcy = (ll.y + ur.y) / 2;
  w_o->ll.x += oldcx - newcx;
  w_o->ur.x += oldcx - newcx;
  w_o->ll.y += oldcy - newcy;
  w_o->ur.y += oldcy - newcy;
  show_comp();
  if (xform != 0)
    modify(COMP);
}


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

c_cell *which_open_comp(comp_list *c, point p, point ll)
{
  /* Function returns */
  /* which subcell of c contains pen point p    */
  /* offset ll allows for recursive search */
  /* NOTE: ll is NO LONGER USED!!! */
  c_cell *Result, *t_sc, *old_t_sc, *select_scan;
  boolean cont;
  point p1, p2;
  tr_matrix old_matrix;

  TRY(try9);
    if (select_in_progress_c && last_selected_object_c != NULL)
    {  /* get out of select mode */
      show_message("Sorry, no manual select with POKE", false);
      unhighlight_c(last_selected_object_c);
      select_scan = select_list_head_c;
      while (select_list_head_c != NULL) {
	select_scan = select_list_head_c->next;
	recl_c_c_cell(&select_list_head_c);
	select_list_head_c = select_scan;
      }
      last_selected_object_c = NULL;
      select_in_progress_c = false;
    }
    t_sc = c->data;
    cont = true;
    while (cont) {
      if (t_sc == NULL) {
	cont = false;
	break;
      }
      old_matrix = tr_ctm;
      pl_tran(t_sc->ll.x, t_sc->ll.y);
      pl_xform(t_sc->xform);

      p1 = scale_down(transform_point(zero_point));
      p2 = scale_down(transform_point(change_to_point(t_sc->ur.x - t_sc->ll.x,
					t_sc->ur.y - t_sc->ll.y)));
      /*
writeln ('Trying to compare: pen: ',p.x:6,',',p.y:6);
writeln ('        with ll object: ',p1.x:6,',',p1.y:6);
writeln ('             ur       : ',p2.x:6,',',p2.y:6);
writeln;
*/

      if ((p.x >= p1.x && p.x <= p2.x || p.x <= p1.x && p.x >= p2.x) &&
	  (p.y >= p1.y && p.y <= p2.y || p.y <= p1.y && p.y >= p2.y))
      {  /* we are inside the comp cell */
	if (t_sc->status == OPENED && t_sc->tag == COMP) {
	  old_t_sc = t_sc;
	  t_sc = which_open_comp(t_sc->UU.U1.c_d, p, zero_point);
	  if (t_sc == NULL)
	    t_sc = old_t_sc;
	  cont = false;
	} else if (t_sc->status == JUST_CLOSED) {
	  t_sc->status = CLOSED;
	  t_sc = NULL;   /* kludge to handle closure correctly */
	  cont = false;
	} else
	  cont = false;
      } else
	t_sc = t_sc->next;
      tr_ctm = old_matrix;   /* pop back old matrix */
    }
    Result = t_sc;
  RECOVER(try9);
    if (P_escapecode == 10)
      _Escape(P_escapecode);
    else {
      show_error("WHICH_OPEN_COMP", false);
      _Escape(10);
    }
  ENDTRY(try9);
  return Result;
}


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

boolean top_level_cell(comp_list *scan)
{
  /* returns true if scan points to element in .next list of
     list pointed to by comp_cells; */
  boolean temp;
  comp_list *scan1;

  temp = false;
  scan1 = comp_cells;
  do {
    temp = (scan == scan1);
    scan1 = scan1->next;
  } while (!(scan1 == NULL || scan1 == comp_cells || temp));
  return temp;
}


void close_a_cell(comp_list *scan2)
{
  /* restore original data structure, reclaiming nodes as necessary */
  /*                                                                 */
  c_cell *scan1;

  TRY(try10);
    if (!top_level_cell(scan2)) {
      scan1 = scan2->data;
      while (scan1 != NULL) {
	if (scan1->tag == COMP)   /* delete it */
	  close_a_cell(scan1->UU.U1.c_d);
	else  /* it is a geometry cell */
	  scan1->status = CLOSED;
	scan1 = scan1->next;
      }
      recl_c_cell(&scan2);
    }
  RECOVER(try10);
    if (P_escapecode == 10)
      _Escape(10);
    else {
      show_error("CLOSE_A_CELL", true);
      _Escape(10);
    }
  ENDTRY(try10);
}


boolean close_poked_cells(void)
{
  /* run down the whole list from comp_cells, and close all OPENED sub_cells */
  boolean Result;
  c_cell *scan1;
  comp_list *scan2;

  TRY(try11);
    Result = false;
    scan2 = comp_cells;
    do {
      scan1 = scan2->data;
      while (scan1 != NULL) {
	if (scan1->tag == COMP) {  /* close all sub_cells */
	  if (scan1->status == OPENED)
	    Result = true;
	  close_a_cell(scan1->UU.U1.c_d);
	  scan1->status = CLOSED;
	  scan1->UU.U1.c_d = scan1->UU.U1.old_c_d;
	} else {  /* it is a geometry cell */
	  if (scan1->status == OPENED)
	    Result = true;
	  scan1->status = CLOSED;
	}
	scan1 = scan1->next;
      }
      scan2 = scan2->next;
    } while (scan2 != comp_cells && scan2 != NULL);
  RECOVER(try11);
    show_error("CLOSE_POKED_CELLS", true);
  ENDTRY(try11);
  return Result;
}


void open_all_comp_cells(boolean show_geom)
{
  /*if show_geom, then open right down to the geometry cell level */
  c_cell *scan1;
  comp_list *scan2;

  TRY(try12);
    close_poked_cells();
    scan2 = comp_cells;
    do {
      scan1 = scan2->data;
      while (scan1 != NULL) {
	if (scan1->tag == COMP) {
	  /* if scan1^.xform = 0 then */
	  /* open it up */
	  scan1->status = OPENED;
	  scan1->UU.U1.old_c_d = scan1->UU.U1.c_d;
	} else {  /* it is a geometry cell */
	  if (show_geom)
	    scan1->status = OPENED;
	  else
	    scan1->status = CLOSED;
	}
	scan1 = scan1->next;
      }
      scan2 = scan2->next;
    } while (scan2 != comp_cells && scan2 != NULL);
  RECOVER(try12);
    show_error("OPEN_ALL_COMP_CELLS", true);
  ENDTRY(try12);
}


void poke_c_cells(point start)
{
  c_cell *d_obj, *scan, *scan2;

  /*  start : point;   */
  /* get cursor position once depressed */
  /*debounce();*/
  /*   REPEAT
        t_pp := track;
     UNTIL t_pp.menu = 0;
     start := scale_down(change_to_point(t_pp.x,t_pp.y));    */
  start = scale_down(start);
  /* determine which cell it is in      */
  d_obj = which_open_comp(comp_cells, start, zero_point);

  /* if d_obj <> NIL then
      if d_obj^.tag = COMP then
         writeln ('Pen pressed within ',d_obj^.c_d^.name);
   */

  if (d_obj != NULL) {
    if (d_obj->status == CLOSED) {   /* and (d_obj^.xform = 0) */
      /* mark it open, and create copies of its children */
      d_obj->status = OPENED;
      if (d_obj->tag == COMP) {
	d_obj->UU.U1.old_c_d = d_obj->UU.U1.c_d;
	    /* save copy of original link */
	d_obj->UU.U1.c_d = get_c_cell();   /* make copy of link     */
	*d_obj->UU.U1.c_d = *d_obj->UU.U1.old_c_d;
	scan = d_obj->UU.U1.c_d->data;
	    /* point to children of original link */

	scan2 = get_c_c_cell();
	    /* create copy of first element in c_cell list */
	*scan2 = *scan;
	/* get a new unique prefix for this cell */
	/* scan2^.prefixid := get_new_prefixid (scan2^.name);*/
	/* NO -- you want the children's names to be unchanged */

	scan2->status = CLOSED;
	scan2->next = NULL;

	d_obj->UU.U1.c_d->data = scan2;
	scan = scan->next;
	TRY(try13);
	  while (scan != NULL) {
	    scan2 = get_c_c_cell();
	    *scan2 = *scan;
	    /* get a new unique prefix for this cell */
	    /* scan2^.prefixid := get_new_prefixid (scan2^.name);*/
	    /* NO -- you want the children's names to be unchanged */
	    scan2->status = CLOSED;
	    scan2->next = d_obj->UU.U1.c_d->data->next;
	    d_obj->UU.U1.c_d->data->next = scan2;
	    scan = scan->next;
	  }
	RECOVER(try13);
	  show_error("Died trying to copy array in poke_c_cell", false);
	  _Escape(10);
	ENDTRY(try13);
      }
    } else {
      if (d_obj->status == OPENED) {
	/* if that cell is OPENED, dispose of all its children,
	   and mark it JUST_CLOSED */
	if (d_obj->tag == COMP) {
	  if (!top_level_cell(d_obj->UU.U1.c_d))   /* dispose of children */
	    recl_c_cell(&d_obj->UU.U1.c_d);
	  d_obj->UU.U1.c_d = d_obj->UU.U1.old_c_d;
	      /* restore original links */
	  d_obj->status = JUST_CLOSED;
	} else  /* its a geometry node, so just mark it closed */
	  d_obj->status = JUST_CLOSED;
      }
    }
  }
  /*   if d_obj^.status = JUST_CLOSED then
        begin
          write ('Found JUST_CLOSED cell: ');
          if d_obj^.tag = COMP then writeln (d_obj^.c_d^.name)
                               else writeln (d_obj^.g_d^.name);
        end;
   */
  /* if the child is a geom cell, draw the geometry */
  /* call refresh (this should draw the geometry) */
  show_comp();
}


/* Local variables for plot_comp: */
struct LOC_plot_comp {
  short plot_layer;   /* current plotting layer */
} ;

Local void plot_geom_in_comp(node *p, struct LOC_plot_comp *LINK)
{
  while (p != NULL) {
    if (p->layer == LINK->plot_layer)
      pl_box(p->ll.x, p->ll.y, p->ur.x, p->ur.y);
    plot_geom_in_comp(p->child, LINK);
    p = p->next;
  }
}

Local void plot_routing(routing *rt, struct LOC_plot_comp *LINK)
{
  /* draw the routing within a composition cell */
  routing *rt_ptr, *rt_horiz;

  rt_horiz = rt;
  while (rt_horiz != NULL) {
    rt_ptr = rt_horiz;
    while (rt_ptr != NULL) {
      if (rt_ptr->layer == LINK->plot_layer) {
	/* writeln (rt_ptr^.pt1.x, rt_ptr^.pt1.y, rt_ptr^.pt2.x, rt_ptr^.pt2.y); */
	pl_move(rt_ptr->pt1.x, rt_ptr->pt1.y);
	pl_draw(rt_ptr->pt2.x, rt_ptr->pt2.y);
      }
      rt_ptr = rt_ptr->to_point;
    }
    rt_horiz = rt_horiz->next;
  }
}

Local void plot_comp_cell(c_cell *root, struct LOC_plot_comp *LINK)
{
  Char pr_name[81];
  tr_matrix old_ctm;

  old_ctm = tr_ctm;
  TRY(try14);
    while (root != NULL) {
      tr_ctm = old_ctm;
      if (root->status == OPENED) {   /* status<>OPENED */
	pl_tran(root->ll.x, root->ll.y);
	pl_xform(root->xform);
	if (root->tag == COMP) {
	  plot_routing(root->UU.U1.c_d->routing_, LINK);
	  plot_comp_cell(root->UU.U1.c_d->data, LINK);
	} else
	  plot_geom_in_comp(root->UU.g_d->data, LINK);
      }  /* status=OPENED */
      else if (LINK->plot_layer == comp_box) {
	pl_tran(root->ll.x, root->ll.y);
	pl_xform(root->xform);
	pl_box(0, 0, root->ur.x - root->ll.x, root->ur.y - root->ll.y);
	if (root->tag == GEOM)
	  strcpy(pr_name, root->UU.g_d->name);
	else
	  strcpy(pr_name, root->UU.U1.c_d->name);
	pl_text_in_box(0, 0, root->ur.x - root->ll.x, root->ur.y - root->ll.y,
		       pr_name);
      }
      root = root->next;   /* deal with its siblings */
    }
  RECOVER(try14);
    if (P_escapecode == 10)
      _Escape(10);
    else {
      if (P_escapecode != -20)
	show_error("Error in procedure PLOT_COMP_CELL", false);
      _Escape(10);
    }
  ENDTRY(try14);
  tr_ctm = old_ctm;

  /* cell must be closed, so draw it */
}

Local void plot_reference_marks(struct LOC_plot_comp *LINK)
{
  FILE *labelfile;
  Char str[81], textlabel[81];
  long x, y, junk;
  Char STR2[256];
  Char *TEMP;

  labelfile = NULL;
  TRY(try15);
    TRY(try16);
      if (labelfile != NULL)
	labelfile = freopen("LABELS.TEXT", "r", labelfile);
      else
	labelfile = fopen("LABELS.TEXT", "r");
      if (labelfile == NULL) {
	P_escapecode = -10;
	P_ioresult = FileNotFound;
	goto _Ltry16;
      }
    RECOVER2(try16,_Ltry16);
      /* no file found, so get out */
      goto _L1;
    ENDTRY(try16);
    printf("Plotting labels from file:  LABELS.TEXT\n");
    pl_color(1);
    while (fgets(str, 81, labelfile) != NULL) {
      TEMP = strchr(str, '\n');
      if (TEMP != NULL)
	*TEMP = 0;
      sscanf(str, "%ld%ld%80s%ln", &x, &y, textlabel, &junk);
      junk++;
      strcpy(STR2, strltrim(textlabel));
      strcpy(textlabel, STR2);
      strcpy(textlabel, strrtrim(strcpy(STR2, textlabel)));
      pl_move(x - 1, y - 1);
      pl_draw(x + 1, y + 1);
      pl_move(x + 1, y - 1);
      pl_draw(x - 1, y + 1);
      pl_move(x + 1, y);
      pl_text(textlabel);
    }
    if (labelfile != NULL)
      fclose(labelfile);
    labelfile = NULL;
_L1: ;
  RECOVER(try15);
    if (P_escapecode == 10)
      _Escape(10);
    else {
      if (P_escapecode != -20)
	show_error("Error in procedure plot_reference_mark", false);
      _Escape(10);
    }
  ENDTRY(try15);
  if (labelfile != NULL)
    fclose(labelfile);
}


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

/* Plot the composition buffer */
void plot_comp(void)
{  /* plot */
  struct LOC_plot_comp V;
  comp_list *bb, *scan;
  c_cell *p;
  Char message[81];
  long i;   /* for STRWRITE */
  long llx, lly, urx, ury;
  plotter_disp_info *WITH;
  Char STR2[81];

  TRY(try17);
    if (plot_setup()) {
      /* find *COMP* buffer */
      scan = comp_cells;
      do {
	scan = scan->next;
      } while (strcmp(scan->name, "*COMP*") && scan != comp_cells &&
	       scan != NULL);
      if (scan == NULL) {
	show_message("\007This should never happen in PLOT_COMP", false);
	P_escapecode = 10;
	goto _Ltry17;
      }
      p = scan->data;

      /* initialize plot window */
      bb = scan;
      set_c_bb(bb);
      pl_scaleto(bb->ll.x, bb->ll.y, bb->ur.x, bb->ur.y, true);

      pl_color(1);
      plot_reference_marks(&V);   /* add comments to plot */

      for (V.plot_layer = min_layer; V.plot_layer <= max_layer; V.plot_layer++) {
	WITH = &layers[V.plot_layer - min_layer].plot;
	if (WITH->color != 0) {   /* this layer has a pen */
	  pl_color(WITH->color);
	  /* should do something about linestyles... */
	  plot_comp_cell(p, &V);
	  plot_routing(comp_cells->routing_, &V);
	}  /* for */
      }


      /* write cell name, size, and date */
      pl_color(layers[comp_box - min_layer].plot.color);
      message[0] = '\0';
      if (*curr_comp_cell != '\0') {
	sprintf(message, "%s:  %ld x %ld LAMBDA    %s",
		curr_comp_cell, bb->ur.x - bb->ll.x, bb->ur.y - bb->ll.y,
		get_date_string(STR2));
	i = strlen(message) + 1;
      } else {
	sprintf(message, "<not made>:  %ld x %ld LAMBDA    %s",
		bb->ur.x - bb->ll.x, bb->ur.y - bb->ll.y,
		get_date_string(STR2));
	i = strlen(message) + 1;
      }
      pl_scaleoff();
      pl_getsize(&llx, &lly, &urx, &ury);
      pl_move(llx + 10, lly + 50);
      pl_text(message);
      pl_end();
    }
  RECOVER2(try17,_Ltry17);
    if (P_escapecode != 10)
      show_error("Error in procedure: PLOT_COMP", false);
    plot_cleanup();
    waitfor(300);
    m_graphics_on();
    m_alpha_off();
  ENDTRY(try17);
}


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


void get_comp_name(point start)
{
  c_cell *m_obj;
  Char newname[11];
  /*t_oc     : c_cell;*/
  point ll, ur;
  Char *TEMP;

  /*debounce();*/   /* Get the pen up.                   */
  start = scale_down(start);
  m_obj = which_comp(comp_cells, start);
      /* Get the object.                   */
  if (m_obj == NULL)   /* If one was selected...            */
    return;
  xor_on();
  gstate.dotted = true;
  reset_layer();   /*####Weirdness - need COMPBOX layer */
  xform_node(m_obj, &ll, &ur);
  ll = scale_up(ll);
  ur = scale_up(ur);
  m_color(BR_WHITE);
  draw_rbb(ll, ur);
  /*t_oc := xform_node(m_obj^);*/
  /*draw_rbb(t_oc.ll,t_oc.ur);*/
  alpha_screen(CLR);
  m_alpha_on();
  putchar('\n');
  if (*m_obj->prefix == '\0')
    printf("Enter cell prefix: ");
  else
    printf("Enter new cell prefix [%s]: ", m_obj->prefix);
  fgets(newname, 11, stdin);
  TEMP = strchr(newname, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  if (*newname != '\0') {
    modify(COMP);
    if (strpos2(newname, ".", 1) == 0)
      strcpy(m_obj->prefix, newname);
    else {
      if (strlen(newname) > 1)
	printf("WARNING:  illegal period (.) found in name: %s\n", newname);
      printf("Old name [%s] deleted\n", m_obj->prefix);
      *m_obj->prefix = '\0';
    }
  }
  xor_off();
  gstate.dotted = false;
  show_comp();
}


Local void fixup_c_cell(c_cell *data);
Local void reset_c_cell(c_cell *data);

Local void fixup_comp_cell(comp_list *data)
{
  /* fixup BBOXes of subcells withing a comp cell, IF not yet done */
  point maxur, minll, newll, newur;
  c_cell *scan;

  if (data == NULL || data->correct_mbb)
    return;
  /* writeln ('fixup_comp_cell called on: ',data^.name);  */
  scan = data->data;
  if (data->data != NULL) {
    fixup_c_cell(data->data);
    xform_node(data->data, &minll, &maxur);
    scan = data->data->next;
  }
  while (scan != NULL) {   /* traverse list to find max and min */
    fixup_c_cell(scan);
    xform_node(scan, &newll, &newur);   /* get real extent */
    if (newll.x < minll.x)
      minll.x = newll.x;
    if (newll.y < minll.y)
      minll.y = newll.y;
    if (newur.x > maxur.x)
      maxur.x = newur.x;
    if (newur.y > maxur.y)
      maxur.y = newur.y;
    scan = scan->next;
  }
  if (data->data != NULL) {
    data->ll = minll;
    data->ur = maxur;
  }
  data->correct_mbb = true;
}

Local void fixup_c_cell(c_cell *data)
{
  if (data == NULL || data->correct_mbb)
    return;
  switch (data->tag) {

  case COMP:
    fixup_comp_cell(data->UU.U1.c_d);
    /* writeln ('  fixup_c_cell called on: ', data^.c_d^.name); */
    data->ll = change_to_point(data->ll.x + data->UU.U1.c_d->ll.x,
			       data->ll.y + data->UU.U1.c_d->ll.y);
    data->ur = change_to_point(data->ll.x + data->UU.U1.c_d->ur.x,
			       data->ll.y + data->UU.U1.c_d->ur.y);
    break;

  case GEOM:
    /* writeln ('  fixup_c_cell called on: ', data^.g_d^.name);  */
    data->ll = change_to_point(data->ll.x + data->UU.g_d->ll.x,
			       data->ll.y + data->UU.g_d->ll.y);
    data->ur = change_to_point(data->ll.x + data->UU.g_d->ur.x,
			       data->ll.y + data->UU.g_d->ur.y);
    break;
  }/* case */
  data->correct_mbb = true;
}

Local void reset_comp_cell(comp_list *data)
{
  c_cell *scan;

  /* fixup BBOXes of subcells withing a comp cell */
  if (!(data != NULL && data->correct_mbb))
    return;
  /* writeln ('reset_comp_cell called on: ',data^.name);   */
  data->correct_mbb = false;   /* reset flag */
  scan = data->data;
  while (scan != NULL) {   /* traverse list to reset all*/
    reset_c_cell(scan);
    scan = scan->next;
  }
}

Local void reset_c_cell(c_cell *data)
{
  if (!(data != NULL && data->correct_mbb))
    return;
  data->correct_mbb = false;
  if (data->tag == COMP) {
    reset_comp_cell(data->UU.U1.c_d);
    /* writeln ('  reset_c_cell called on: ',data^.c_d^.name); */
  }

  /* writeln ('  reset_c_cell called on: ',data^.g_d^.name) */
}


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





/*$if false$
    { this stuff works, but is TOO slow }

   procedure fixup_c_cell (data : c_ptr); forward;

   procedure fixup_comp_cell (data : comp_ptr);
    { fixup BBOXes of subcells withing a comp cell }
    var maxur, minll, newll, newur : point;
        scan : c_ptr;
    begin
      if data <> nil then
        begin
           { writeln ('fixup_comp_cell called on: ',data^.name); }
           scan := data^.data;
           if data^.data <> NIL then begin
                   fixup_c_cell (data^.data);
                   xform_node (data^.data, minll, maxur);
                   scan := data^.data^.next;
                end;
           while scan <> nil do    { traverse list to find max and min }
             begin
               fixup_c_cell (scan);
               xform_node (scan, newll, newur);    { get real extent }
               if newll.x < minll.x then minll.x := newll.x;
               if newll.y < minll.y then minll.y := newll.y;
               if newur.x > maxur.x then maxur.x := newur.x;
               if newur.y > maxur.y then maxur.y := newur.y;
               scan := scan^.next;
             end;
           if data^.data <> nil then begin
                      data^.ll := minll;
                      data^.ur := maxur;
                   end;
        end;
    end;

   procedure fixup_c_cell (data : c_ptr);
    begin
      if data <> nil then
        begin
            case data^.tag of
            COMP : begin
                     fixup_comp_cell (data^.c_d);
                     { writeln ('  fixup_c_cell called on: ', data^.c_d^.name); }
                     data^.ll := change_to_point (data^.ll.x+data^.c_d^.ll.x,
                                                  data^.ll.y+data^.c_d^.ll.y);
                     data^.ur := change_to_point (data^.ll.x+data^.c_d^.ur.x,
                                                  data^.ll.y+data^.c_d^.ur.y);
                   end;
            GEOM : begin
                     { writeln ('  fixup_c_cell called on: ', data^.g_d^.name);  }
                     data^.ll := change_to_point (data^.ll.x+data^.g_d^.ll.x,
                                                  data^.ll.y+data^.g_d^.ll.y);
                     data^.ur := change_to_point (data^.ll.x+data^.g_d^.ur.x,
                                                  data^.ll.y+data^.g_d^.ur.y);
                   end;
            end;  { case }
        end;
    end;
$end$*/

void update_comp_mbb(void)
{
  /* traverse the data structure from comp_cells on,
     in order to correctly reflect minimum bounding boxes,
     as the cells are modified */
  comp_list *scan;
  boolean starting;

  TRY(try18);
    printf("update_comp_mbb called\n");
    scan = comp_cells;
    set_c_bb(comp_cells);   /* add a MBB to comp buffer */
    starting = true;   /* update ALL COMP cells       */
    while (starting || scan != comp_cells && scan != NULL) {
      starting = false;
      fixup_comp_cell(scan);
      if (scan != NULL)
	scan = scan->next;
    }

    scan = comp_cells;
    starting = true;   /* reset ALL COMP cells  flags     */
    while (starting || scan != comp_cells && scan != NULL) {
      starting = false;
      reset_comp_cell(scan);   /* reset the correct_mbb flag */
      if (scan != NULL)
	scan = scan->next;
    }

    set_c_bb(comp_cells);   /* add a new, correct MBB to comp buffer */
    m_alpha_off();
  RECOVER(try18);
    show_error("Procedure UPDATE_COMP_MBB", false);
    waitfor(300);
    m_alpha_off();
  ENDTRY(try18);
}


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

short deferred_depth(void)
{
  deferred_rec *tmp_deferred;
  short depth;

  tmp_deferred = deferred_stack;
  depth = 0;
  while (tmp_deferred != NULL) {
    tmp_deferred = tmp_deferred->next;
    depth++;
  }
  return depth;
}


/* Local variables for disp_memory: */
struct LOC_disp_memory {
  long used;   /* how much memory used since startup */
  long free;   /* how much free on lists */
  long alloc;   /* how much accounted for by allocation routines */
} ;

Local void show(Char *n, short all, short num, short size,
		struct LOC_disp_memory *LINK)
{
  if (size & 1)
    size++;
  printf("%s%*s%4d   %7d%7d%6.1f%%  %7d%7d%6.1f%%\n",
	 n, (int)(12 - strlen(n)), "", size, all, all * size,
	 all * size * 100.0 / LINK->used, num, num * size,
	 num * size * 100.0 / LINK->used);
  LINK->free += num * size;
  LINK->alloc += all * size;
}


void disp_memory(void)
{
  struct LOC_disp_memory V;
  long t_mem;
  Char ch;
  FILE *TEMP;

  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  t_mem = asm_memavail();
  V.used = init_mem - t_mem;
  V.free = 0;
  V.alloc = 0;

  printf("       WOL   Version #%s;  Compiled: %s\n\n",
	 Version, Compilation_date);
  printf("Initial:  %8ld bytes, 100.0%%\n", init_mem);
  printf("Allocated:%8ld bytes, %5.1f%%\n",
	 V.used, (double)V.used / init_mem * 100);
  printf("Free heap:%8ld bytes, %5.1f%%\n",
	 t_mem, (double)t_mem / init_mem * 100);
  printf("Threshold:%8ld bytes, %5.1f%%\n\n",
	 mem_thresh, (double)mem_thresh / init_mem * 100);
  TEMP = stdout;
  /*writeln('123456789012123456712345671234567123456712123456712345671234567');*/
/* p2c: wol_cmd.text, line 3400:
 * Note: Taking address of stdout; consider setting VarFiles = 0 [144] */
  core_stats(&TEMP);
  /*$if false$
   writeln('  Type       Size      Allocated    % of         Free      % of');
   writeln(' of node    of node  number  bytes  used    number  bytes  used');
   writeln;
   show('Wire',     alloc_nodes,    num_nodes,    sizeof(node));
   show('Geom cell',alloc_g_cells,  num_g_cells,  sizeof(cell));
   show('Comp cell',alloc_c_cells,  num_c_cells,  sizeof(comp_list));
   show('Comp cont',alloc_c_c_cells,num_c_c_cells,sizeof(c_cell));
   show('Cif nodes',alloc_a_w_nodes,num_a_w_nodes,sizeof(a_w_node));
   show('Def nodes',deferred_depth, deferred_depth,sizeof(deferred_rec));
   show('Rtng wire',alloc_routing_nodes,num_routing_nodes,sizeof(routing));
   show('Port node',alloc_port_nodes,num_port_nodes,sizeof(port_node));
   writeln('All lists                 ',
                  alloc:7,alloc/used*100:6:1,'%         ',
                  free:7,free/used*100:6:1,'%');
   writeln;
   writeln('Total memory available on free lists: ',free:1,' bytes (',
           free/init_mem*100:0:1,'% total memory)');
$end$*/
  printf("\nPress any key or pen to continue: ");
  ch = wait_pen_or_kbd();
  m_graphics_on();
  m_alpha_off();
}


void do_bool(boolean *b, Char *p)
{
  Char ch;

  fputs(p, stdout);
  if (*b)
    printf("[Y] ");
  else
    printf("[N] ");
  ch = nk_getkey();   /*if ch > ' ' then write (ch);*/
  if (ch == 'y' || ch == 'n' || ch == 'Y' || ch == 'N')
    *b = (ch == 'y' || ch == 'Y');
  if (*b)
    printf("Yes\n");
  else
    printf("No\n");
}


/* Local variables for user_options: */
struct LOC_user_options {
  Char old_technology[81];
  short old_disp_style, old_background_color, old_lambda_to_microns;
  long old_mem_thresh, old_initial_cif_symbol_number;
  boolean old_prompt_cellname, old_prompt_filename, old_auto_refresh,
	  old_edges_only, old_bbox_nobbox, old_display_ports,
	  old_Manhattan_routing, old_fleshed_out_routing;
} ;

Local void save_state(struct LOC_user_options *LINK)
{
  LINK->old_lambda_to_microns = lambda_to_microns;
  LINK->old_disp_style = disp_style;
  LINK->old_prompt_cellname = prompt_cellname;
  LINK->old_prompt_filename = prompt_filename;
  LINK->old_auto_refresh = auto_refresh;
  LINK->old_edges_only = edges_only;
  LINK->old_bbox_nobbox = bbox_nobbox;
  LINK->old_display_ports = display_ports;
  LINK->old_Manhattan_routing = manhattan_routing;
  LINK->old_fleshed_out_routing = fleshed_out_routing;
  LINK->old_background_color = background_color;
  LINK->old_mem_thresh = mem_thresh;
  LINK->old_initial_cif_symbol_number = initial_cif_symbol_number;
  strcpy(LINK->old_technology, technology);
}

Local void restore_state(struct LOC_user_options *LINK)
{
  lambda_to_microns = LINK->old_lambda_to_microns;
  disp_style = LINK->old_disp_style;
  prompt_cellname = LINK->old_prompt_cellname;
  prompt_filename = LINK->old_prompt_filename;
  auto_refresh = LINK->old_auto_refresh;
  edges_only = LINK->old_edges_only;
  bbox_nobbox = LINK->old_bbox_nobbox;
  display_ports = LINK->old_display_ports;
  manhattan_routing = LINK->old_Manhattan_routing;
  fleshed_out_routing = LINK->old_fleshed_out_routing;
  background_color = LINK->old_background_color;
  mem_thresh = LINK->old_mem_thresh;
  initial_cif_symbol_number = LINK->old_initial_cif_symbol_number;
  strcpy(technology, LINK->old_technology);

  m_setcolor(0, background_color, background_color, background_color);
  read_tech_file(technology);
}


/*$if false$
PROCEDURE user_options;
{ this is intended to allow the user to configure things as he wishes }
{ these variables are left untouched from one invokation of WOL to
  the next, if the program is P-loaded }
var r,g,b,p : integer;
    l : real;
    ch : char;
    s:string255;
    emergency : boolean;  { allow emergency action on the buffers }
begin
   TRY
      m_graphics_off; alpha_screen(clr); m_alpha_on;
         writeln('       WOL   Version #',Version,
                                 ';  Compiled: ',Compilation_date);
         writeln;
         writeln;

      { BACKGROUND COLOR }
         writeln ('Enter background color: ');
         writeln ('    Enter one digit in range 0..15');
         writeln ('    e.g. 2 for lt. grey, 0 for black');
         write   ('color [',background_color:0,']? ');
         readln(s);
         if strlen(s)>0 then
            TRY
               strread(s,1,p,r);
               m_setcolor(0, r,r,r);
               background_color := r;
            RECOVER
               if escapecode<>-10 then escape(escapecode) else
                  writeln('Requires an integer.  No change performed');
      { NEW LAMBDA }
         write ('Enter lambda in microns [',lambda_to_microns/100.0:0:2,']: ');
         readln(s);
         if strlen(s)>0 then
            TRY
               strread(s,1,p,l);
               lambda_to_microns := TRUNC (100 * l);
            RECOVER
               if escapecode<>-10 then escape(escapecode) else
                  writeln('No change performed');
      { NEW MEMORY THRESHOLD }
         write ('Enter new memory threshold [',mem_thresh:1,' bytes]: ');
         readln(s);
         if strlen(s)>0 then
            TRY
               strread(s,1,p,r);
               mem_thresh := r;
            RECOVER
               if escapecode<>-10 then escape(escapecode) else
                  writeln('No change performed');
      { NEW TECHNOLOGY FILE }
         write('Enter new technology [',technology,']: ');
         readln(s);
         if s<>'' then read_tech_file(s);
         layers_show_all;

      { AUTO-REFRESH }
         do_bool(auto_refresh,'Auto-refresh? ');

      { PROMPT FILENAMES }
         do_bool(prompt_filename,'Prompt for file names? ');

      { PROMPT CELLNAMES }
         do_bool(prompt_cellname,'Prompt for cell names? ');

      { CLIP BOXES }
         do_bool(debug_clip,'Debug: Clipping? ');

      { MANHATTAN ROUTING }
         do_bool(Manhattan_routing,'Manhattan routing only? ');
      { FLESHED OUT ROUTING }
         do_bool(Fleshed_out_routing,'Fleshed out routing? ');

      { EMERGENCY }
         emergency := false;
         do_bool(emergency, 'Emergency buffer action? ');
         if emergency then  begin
            emergency := false;
            do_bool(emergency, #139'WARNING: your current buffer(s) will be lost.'+
                               #136'  Proceed? ');
            if emergency then begin
              emergency := false;
              do_bool(emergency, '   KILL Geometry buffer? ');
              if emergency then
                 begin
                    curr_geom_cell := '';  { Forget cell name now }
                    { do not  recl_nodes(main)  --  rather throw memory away }
                    geom_cells^.data := NIL;
                    geom_cells^.modified := false;
                    main := NIL;
                    refresh_geom;
                    m_graphics_on; m_alpha_on;
                    zoom_it(1);
                 end;
              emergency := false;
              do_bool(emergency, '   KILL Composition buffer? ');
              if emergency then
                 begin
                    comp_cells^.data := NIL;
                    comp_cells^.routing := NIL;
                    comp_cells^.modified := false;
                    curr_comp_cell := '';   { forget the cell name we were editing }
                    zoom_it(1);
                 end;
           end;
         end;

      writeln;
   RECOVER
      show_error('Error in USER_OPTIONS',false);
   m_graphics_on; m_alpha_off;
end;
$end$*/


void user_options(void)
{
  /* this is intended to allow the user to configure things as he wishes */
  /* these variables are left untouched from one invokation of WOL to
     the next, if the program is P-loaded */
  struct LOC_user_options V;
  dispRec *opt;
  boolean redraw;

  TRY(try19);
    m_graphics_off();
    alpha_screen(CLR);
    m_alpha_on();
    strcpy(V.old_technology, technology);
    printf("       WOL   Version #%s;  Compiled: %s\n\n\n",
	   Version, Compilation_date);
    save_state(&V);
    cmd_options();
    opt = dispHead;
    redraw = false;
    while (opt != NULL) {
      switch ((dispSpecials)opt->special) {

      case sp_none:   /* do nothing */
	break;

      case sp_tab:   /* do nothing */
	break;

      case sp_tech:
	if (strcmp(V.old_technology, opt->UU.U0.strcur) &&
	    *opt->UU.U0.strcur != '\0') {
	  strcpy(technology, opt->UU.U0.strcur);
	  read_tech_file(technology);
	}
	/*  layers_show_all;  dont do this */
	break;

      case sp_lambda:   /**/
	break;

      case sp_back_color:
	m_setcolor(0, background_color, background_color, background_color);
	break;

      case sp_redraw:
	redraw = true;
	break;
      }
      opt = opt->next;
    }
    if (redraw)
      refresh_geom();


  RECOVER(try19);
    if (P_escapecode != -20)
      show_error("Error in USER_OPTIONS", false);
    else {
      /* restore old state */
      show_message("User <ABORT> from OPTIONS.  Old state maintained.", true);
      restore_state(&V);
    }
  ENDTRY(try19);
  m_graphics_on();
  m_alpha_off();
}


typedef Char bool_arrayt[2][15];
typedef Char docaps_arrayt[3][15];

/*   cfnametype = array[cfilekind] of enumStr;                     */
/*   oonametype = array[out_opts] of enumStr;                      */
/*   bsnametype = packed array[bs_actions] of enumStr;             */


const bool_arrayt bool = {
  "Off", "On"
};

const docaps_arrayt caps_ = {
  "No change", "Turn off", "Turn on"
};

/*   cfnames = cfnametype['by suffix','text','ascii','data'];          */
/*   oonames = oonametype['normal','overwrite','del first'];           */
/*   bsnames = bsnametype['stay put','move to eol','move up to eol'];  */

#define infinity        30000


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

void setupDisp(void)
{
  dispHead = NULL;
  dispLine = 0;
  dispShort("Lambda:", &lambda_to_microns, infinity, 1);
      /* dispHead^.special := sp_tab; */
  /* dispEnum ('Fill mode:',fill_boxes,1,0,addr(bool));  */
  dispShort("Display style:", &disp_style, max_styles, 0);
  dispEnum("Short cell name prompt: ", (Char *)(&prompt_cellname), 1, 0, bool);
  dispEnum("Short file name prompt: ", (Char *)(&prompt_filename), 1, 0, bool);
  dispEnum("Quiet CIF IO: ", (Char *)(&quiet_startup), 1, 0, bool);
  dispEnum("Auto refresh: ", (Char *)(&auto_refresh), 1, 0, bool);
  dispEnum("Edge-priority selection: ", (Char *)(&edges_only), 1, 0, bool);
  dispEnum("Disable Hierarchy: ", (Char *)(&disable_heirarchy), 1, 0, bool);
  dispEnum("Display bounding boxes: ", (Char *)(&bbox_nobbox), 1, 0, bool);
  dispEnum("Display ports: ", (Char *)(&display_ports), 1, 0, bool);
  dispEnum("Manhattan routing: ", (Char *)(&manhattan_routing), 1, 0, bool);
  dispEnum("Fleshed-out routing: ", (Char *)(&fleshed_out_routing), 1, 0,
	   bool);
  dispInt("Background color: ", &background_color, 15, 0);
  dispHead->special = (unsigned)sp_back_color;
  dispInt("Memory threshold: ", &mem_thresh, infinity * 1000, 1);
  dispShort("Cif symbol start: ", &initial_cif_symbol_number, infinity, 1);
  /* technology2 and technology3 are the "default" values */
  dispStr("Technology file: ", technology, technology2, technology3);
  dispHead->special = (unsigned)sp_tech;
  numOpt = dispLine;
}

#undef infinity


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

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

void layer_dump(void)
{
  FILE *o;
  Char name[fidleng + 1];
  Char *TEMP;

  o = NULL;
  printf("Dump to what file [ENTER] for /dev/null: ? ");
  fgets(name, fidleng + 1, stdin);
  TEMP = strchr(name, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  if (*name == '\0')
    strcpy(name, "/dev/null");
  if (o != NULL)
    o = freopen(name, "w", o);
  else
    o = fopen(name, "w");
  if (o == NULL)
    _EscIO(FileNotFound);
  dump_layers(&o);
  if (o != NULL)
    fclose(o);
  o = NULL;
  if (o != NULL)
    fclose(o);
}


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

void emerg_buffer_action(void)
{
  boolean emergency;   /* allow emergency action on the buffers */

  TRY(try20);
    /* EMERGENCY */
/* p2c: wol_cmd.text, line 3728:
 * Note: Characters >= 128 encountered [281] */
    show_message(
      "WARNING:  Do NOT answer YES to ANY of the following unless you are \213SURE\210",
      true);
    emergency = false;
    do_bool(&emergency, "Emergency buffer action? ");
    if (emergency) {
      emergency = false;
/* p2c: wol_cmd.text, line 3733: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3734: Note: Character >= 128 encountered [281] */
      do_bool(&emergency,
	"\213WARNING: your current buffer(s) will be lost.\210  Proceed? ");
      if (emergency) {
	emergency = false;
	do_bool(&emergency, "   KILL Geometry buffer? ");
	if (emergency) {
	  *curr_geom_cell = '\0';   /* Forget cell name now */
	  /* do not  recl_nodes(main)  --  rather throw memory away */
	  geom_cells->data = NULL;
	  geom_cells->modified = false;
	  main_ = NULL;
	  refresh_geom();
	  zoom_it(1.0);
	  m_graphics_on();
	  m_alpha_on();
	}
	emergency = false;
	do_bool(&emergency, "   KILL Composition buffer? ");
	if (emergency) {
	  comp_cells->data = NULL;
	  comp_cells->routing_ = NULL;
	  comp_cells->modified = false;
	  *curr_comp_cell = '\0';   /* forget the cell name we were editing */
	  zoom_it(1.0);
	}
      }
    }
    putchar('\n');
  RECOVER(try20);
    show_error("Error in EMERG_BUFFER_ACTION", false);
  ENDTRY(try20);
  m_graphics_on();
  m_alpha_off();
}


void restart_wol(void)
{
  /* attempts to return all dynamic data structures to their respective pools */
  cell *gscan, *next_gscan;
  comp_list *cscan, *next_cscan;
  boolean firsttime;
  routing *rtng, *next_rtng;

  m_alpha_on();
  TRY(try21);
    gscan = geom_cells;
    printf("Reclaiming geometry cells\n");
    firsttime = true;
    while (gscan != NULL && (gscan != geom_cells || firsttime)) {
      firsttime = false;
      printf("   %s\n", gscan->name);
      next_gscan = gscan->next;
      recl_nodes(&gscan->data);
      recl_port_nodes(&gscan->portlist);
      recl_g_cell(&gscan);
      gscan = next_gscan;
    }
    geom_cells = NULL;

  RECOVER(try21);
    if (P_escapecode == 10)
      _Escape(10);
    show_error("ERROR in reclaiming geometry cells:", false);
    waitfor(200);
  ENDTRY(try21);
  TRY(try22);
    printf("Reclaiming GEOM buffer:\n");
    if (main_ != NULL)
      recl_nodes(&main_);
    /* recl_port_nodes ( ????? */
    main_ = NULL;

  RECOVER(try22);
    if (P_escapecode == 10)
      _Escape(10);
    show_error("ERROR in reclaiming geometry buffer:", false);
    waitfor(200);
    main_ = NULL;
  ENDTRY(try22);
  TRY(try23);
    cscan = comp_cells;
    printf("Reclaiming defined composition cells\n");
    firsttime = true;
    while (cscan != NULL && (cscan != comp_cells || firsttime)) {
      firsttime = false;
      printf("   %s\n", cscan->name);
      next_cscan = cscan->next;
      rtng = cscan->routing_;
      while (rtng != NULL) {
	next_rtng = rtng->next;
	recl_routing_node(&rtng);
	rtng = next_rtng;
      }
      recl_c_cell(&cscan);
      cscan = next_cscan;
    }


  RECOVER(try23);
    if (P_escapecode == 10)
      _Escape(10);
    show_error("ERROR in reclaiming composition cells:", false);
    waitfor(200);
  ENDTRY(try23);
  comp_cells = get_c_cell();
  comp_cells->next = comp_cells;
  comp_cells->data = NULL;
  strcpy(comp_cells->name, "*COMP*");
  comp_cells->ll.x = INFIN;
  comp_cells->ll.y = INFIN;
  comp_cells->ur.x = INFIN;
  comp_cells->ur.y = INFIN;
  comp_cells->modified = false;
  wire_width = 4;

  geom_cells = get_g_cell();
  strcpy(geom_cells->name, "*GEOM*");
  geom_cells->next = geom_cells;
  geom_cells->prev = geom_cells;
  geom_cells->data = main_;
  geom_cells->modified = false;

  *curr_geom_cell = '\0';
  *curr_comp_cell = '\0';

  printf("Data structures re-initialized\n");

}


long address(long *foo)
{
  return (*foo);
}


/* Local variables for dump_geom_data: */
struct LOC_dump_geom_data {
  long offset;
} ;

Local void skip_offset(struct LOC_dump_geom_data *LINK)
{
  long i, FORLIM;

  FORLIM = LINK->offset;
  for (i = 1; i <= FORLIM; i++)
    putchar(' ');
}


void dump_geom_data(node *nd, node *parent_node, long offset_)
{
  /* write to the alpha screen the entire data structure, including port lists */
  /* checks if nd^.parent is parent_node -- prints error if not */
  struct LOC_dump_geom_data V;
  port_node *ports;

  V.offset = offset_;
  if (nd == NULL)
    return;
  do {
    skip_offset(&V);
    printf("%d    %ld   addr = %ld\n",
	   nd->layer, (nd->ur.x - nd->ll.x) * (nd->ur.y - nd->ll.y),
	   address((long *)(&nd)));
    if (nd->parent != parent_node) {
      skip_offset(&V);
/* p2c: wol_cmd.text, line 3888: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3889: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3889:
 * Note: WRITE statement contains color/attribute characters [203] */
      printf("\213Parent is: %ld; should be: %ld \210\n",
	     address((long *)(&nd->parent)), address((long *)(&parent_node)));
    }
    ports = nd->portlist;
    while (ports != NULL) {
      skip_offset(&V);
      printf("Port: %10s; side = %c; Address = %ld; next = %ld\n",
	     ports->name, ports->side, address((long *)(&ports)),
	     address((long *)(&ports->next)));
      ports = ports->next;
    }
    dump_geom_data(nd->child, nd, V.offset + 3);
    nd = nd->next;
  } while (nd != NULL);
}


void dump_geom_cells_list(cell *start)
{
  if (start == NULL) {
    printf("\213NIL pointer encountered in geom cell list\210\n");
    return;
  }
/* p2c: wol_cmd.text, line 3908:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3908:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("Geom Cell:  %s;  MBB = (%ld,%ld) (%ld,%ld) ; modified = %s\n",
	 start->name, start->ll.x, start->ll.y, start->ur.x, start->ur.y,
	 start->modified ? " TRUE" : "FALSE");
  if (start->next->prev != start)
    printf("\213  Link error:  curr^.next^.prev <> curr\210\n");
/* p2c: wol_cmd.text, line 3915:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3915:
 * Note: WRITE statement contains color/attribute characters [203] */
  if (start->next != geom_cells)
    dump_geom_cells_list(start->next);
}


void dump_comp_data(comp_list *start)
{
  c_cell *start_ptr;

  if (start == NULL) {
    printf("\213NIL pointer encountered in comp_cells\210\n");
    return;
  }
/* p2c: wol_cmd.text, line 3925:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3925:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("Comp Cell:  %s;  MBB = (%ld,%ld) (%ld,%ld) ; modified = %s\n",
	 start->name, start->ll.x, start->ll.y, start->ur.x, start->ur.y,
	 start->modified ? " TRUE" : "FALSE");
  start_ptr = start->data;
  while (start_ptr != NULL) {
    if (start_ptr->tag == COMP)
      printf("    COMP:  %s;  MBB = (%ld,%ld)(%ld,%ld) ; mod = %s; prefix = \"%s\"\n",
	     start_ptr->UU.U1.c_d->name, start_ptr->ll.x, start_ptr->ll.y,
	     start_ptr->ur.x, start_ptr->ur.y,
	     start_ptr->UU.U1.c_d->modified ? " TRUE" : "FALSE",
	     start_ptr->prefix);
    if (start_ptr->tag == GEOM)
      printf("    GEOM:  %s;  MBB = (%ld,%ld)(%ld,%ld) ; mod = %s; prefix = \"%s\"\n",
	     start_ptr->UU.g_d->name, start_ptr->ll.x, start_ptr->ll.y,
	     start_ptr->ur.x, start_ptr->ur.y,
	     start_ptr->UU.g_d->modified ? " TRUE" : "FALSE",
	     start_ptr->prefix);
    start_ptr = start_ptr->next;
  }
}


void dump_comp_cells_contents(comp_list *start)
{
  c_cell *start_ptr;

  if (start == NULL) {
    printf("\213NIL pointer encountered in comp cell list\210\n");
    return;
  }
/* p2c: wol_cmd.text, line 3955:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3955:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("Comp Cell:  %s;  MBB = (%ld,%ld)(%ld,%ld) ; modified = %s\n",
	 start->name, start->ll.x, start->ll.y, start->ur.x, start->ur.y,
	 start->modified ? " TRUE" : "FALSE");
  start_ptr = start->data;   /* point to sub-cells */
  while (start_ptr != NULL) {
    if (start_ptr->tag == COMP)
      printf("    COMP:  %s;  MBB = (%ld,%ld)(%ld,%ld) ; mod = %s; prefix = \"%s\"\n",
	     start_ptr->UU.U1.c_d->name, start_ptr->ll.x, start_ptr->ll.y,
	     start_ptr->ur.x, start_ptr->ur.y,
	     start_ptr->UU.U1.c_d->modified ? " TRUE" : "FALSE",
	     start_ptr->prefix);
    if (start_ptr->tag == GEOM)
      printf("    GEOM:  %s;  MBB = (%ld,%ld)(%ld,%ld) ; mod = %s; prefix = \"%s\"\n",
	     start_ptr->UU.g_d->name, start_ptr->ll.x, start_ptr->ll.y,
	     start_ptr->ur.x, start_ptr->ur.y,
	     start_ptr->UU.g_d->modified ? " TRUE" : "FALSE",
	     start_ptr->prefix);
    start_ptr = start_ptr->next;
  }
  if (start->next != comp_cells)
    dump_comp_cells_contents(start->next);
}


/* Local variables for show_modified: */
struct LOC_show_modified {
  boolean first;
} ;

Local void show_(Char *s, struct LOC_show_modified *LINK)
{
  if (LINK->first)
    printf("\211\201Modified cells:\210\200");
  else
    putchar(',');
/* p2c: wol_cmd.text, line 3995:
 * Note: Characters >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 3995:
 * Note: WRITE statement contains color/attribute characters [203] */
  if (XPOS + strlen(s) > 78)
    putchar('\n');
  else
    putchar(' ');
  fputs(s, stdout);
  LINK->first = false;
}



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

void show_modified(void)
{
  struct LOC_show_modified V;
  cell *gcells;
  comp_list *ccells;
  Char STR2[84];

  V.first = true;

  gcells = geom_cells;
  do {
    if (gcells->modified) {
      cells_modified = true;
      if (gcells == geom_cells)
	show_("Geometry Buffer", &V);
      else
	show_(gcells->name, &V);
    }
    gcells = gcells->next;
  } while (gcells != geom_cells);

  ccells = comp_cells;
  do {
    if (ccells->modified) {
      cells_modified = true;
      if (ccells == comp_cells) {   /* light blue */
/* p2c: wol_cmd.text, line 4022:
 * Note: Characters >= 128 encountered [281] */
	show_("\214Composition Buffer\210", &V);
      } else {
	sprintf(STR2, "\214%s\210", ccells->name);
/* p2c: wol_cmd.text, line 4023: Note: Character >= 128 encountered [281] */
/* p2c: wol_cmd.text, line 4023: Note: Character >= 128 encountered [281] */
	show_(STR2, &V);
      }
    }
    ccells = ccells->next;
  } while (ccells != comp_cells);
  putchar('\n');
}


/* module WOL_CMD */




/* End. */
