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


/* Change these for testing */


#include "global.h"


#define WOL_CIF_G
#include "wol_cif.h"


#define C_POLY          'P'   /* 80      Ascii character codes.      */
#define C_BOX           'B'   /* 66 */
#define C_LAYER         'L'   /* 76 */
#define C_DEF           'D'   /* 68 */
#define C_START         'S'   /* 83 */
#define C_FINISH        'F'   /* 70 */
#define C_CALL          'C'   /* 67 */
#define C_END           'E'   /* 69 */
#define C_LPAREN        '('   /* 40 */
#define C_RPAREN        ')'   /* 41 */
#define C_SEMI          ';'   /* 59 */
#define C_CR            ' '   /* 32 */
#define C_NAME          '9'   /* 57 */
#define C_PREFIX        '8'   /* 56 */
#define C_WIRE          'W'   /* 87 */


Static port_node *building_ports;
    /* used to build a port list within a cell */
Static Char last_revision_date[81];   /* date a cell was last modified */
Static short last_revision_number;
    /* number of times a cell has been modified */


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

/* Put an extension on a file name.  Return false if something wrong. */
Static boolean dofixname(Char *fname, Char *base, Char *ext_)
{
  boolean Result;
  Char ext[fidleng + 1];
  short i;   /*  counter to check file-name length */
  short last_slash, last_dot;
  Char STR2[164];

  strcpy(ext, ext_);
  Result = false;
  /*upc(fname); */
  /* enforce upper case file names? */
  if (*fname == '\0') {
    show_message("Null file name.", false);
    goto _L1;
  }
  last_slash = 0;
  last_dot = -1;
  i = strlen(fname);
  while (i > 0 && last_slash == 0) {
    if (fname[i - 1] == '.')
      last_dot = i;
    else if (fname[i - 1] == '/' || fname[i - 1] == ':')
      last_slash = i;
    i--;
  }

  if (last_dot > 0) {   /* has an extension */
    if (strlen(fname) - last_slash > 16) {
      show_message("File name too long (>16 characters)", false);
      goto _L1;
    }
  } else {  /* no extension */
    if (strlen(fname) - last_slash + strlen(ext) > 16) {
      sprintf(STR2, "File name too long with \"%s\" (>16 characters)", ext);
      show_message(STR2, false);
      goto _L1;
    }
    strcat(fname, ext);
  }
  sprintf(base, "%.*s",
	  strlen(fname) - last_slash - strlen(ext), fname + last_slash);
  /*writeln('fname=',fname,' base=',base);*/
  Result = true;
_L1:
  return Result;
}


Static boolean exists_file(Char *name)
{
  boolean Result;
  FILE *f;

  f = NULL;
  TRY(try1);
    if (f != NULL)
      f = freopen(name, "rb", f);
    else
      f = fopen(name, "rb");
    if (f == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry1;
    }
    if (f != NULL)
      fclose(f);
    f = NULL;
    Result = true;
  RECOVER2(try1,_Ltry1);
    if (P_escapecode != -10)
      _Escape(P_escapecode);
    Result = false;
  ENDTRY(try1);
  if (f != NULL)
    fclose(f);
  return Result;
}


/* Return TRUE if it is OK to write the given file. */
Static boolean OK_write_file(Char *name, Char *base)
{   /* RETURN */
  boolean Result;
  Char STR1[256], STR2[256];

  Result = true;   /* assume true */
  if (exists_file(name)) {
    Result = false;   /* Now assume false */
    sprintf(STR2, "\n\015File: %s already exists.  Overwrite", name);
    if (!yes_no_quest(STR2))
      goto _L1;
    m_alpha_on();
    putchar('\n');
    TRY(try2);   /* to change the name */
      printf("Changing \"%s\" to \"%s.cfo\"\n", name, base);
      sprintf(STR2, "%s.cfo", base);
      fp_change(name, STR2);
    RECOVER(try2);
      if (P_escapecode != -10)
	_Escape(-10);
      if (P_ioresult != (int)idupfile)
	_Escape(-10);
      sprintf(STR1, "%.*s.cfo", (int)(strlen(name) - 4), name);
      /* writeln('Dup dir entry!!');  */
      fp_remove(STR1);
      sprintf(STR1, "%s.cfo", base);
      fp_change(name, STR1);
    ENDTRY(try2);
    Result = true;
  }
_L1:
  return Result;
}


/* Local variables for write_comp_ports: */
struct LOC_write_comp_ports {
  Char cell_name[fidleng + 1];
  FILE *portfile;
} ;

Local void write_port_list(port_node *p, point max_ur,
			   struct LOC_write_comp_ports *LINK)
{
  point pt1, pt2, pt3;

  max_ur.x /= 2;
  max_ur.y /= 2;
  pt3 = transform_point(max_ur);   /* center of cell */
  while (p != NULL) {
    pt1 = transform_point(p->p1);
    pt2 = transform_point(p->p2);
    fprintf(LINK->portfile, "%s#%s %ld %ld   %ld %ld   ",
	    LINK->cell_name, p->name, pt1.x, pt1.y, pt2.x, pt2.y);
    if (pt1.x == pt2.x) {
      if (pt1.x > pt3.x)
	fprintf(LINK->portfile, "EAST ");
      else
	fprintf(LINK->portfile, "WEST ");
    } else {
      if (pt1.y > pt3.y)
	fprintf(LINK->portfile, "NORTH ");
      else
	fprintf(LINK->portfile, "SOUTH ");
    }
    fprintf(LINK->portfile, "%ld %s %s\n", p->width, p->layer, p->signaltype);

    p = p->next;
  }
}

Local void write_comp_ports_2(c_cell *root, struct LOC_write_comp_ports *LINK)
{
  /* stacks up a transformation matrix */
  point tp2;
  tr_matrix old_matrix;
  bb_states bb_save;
  Char oldcell_name[fidleng + 1];

  old_matrix = tr_ctm;
  bb_save = bb_state;

  if (asm_memavail() < min_mem_recurse) {
    show_message("\007Low on memory in WRITE_COMP_PORTS", false);
    return;
  }
  TRY(try3);
    while (root != NULL) {
      bb_state = bb_save;
      strcpy(oldcell_name, LINK->cell_name);

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

      if (root->tag == COMP) {
	sprintf(LINK->cell_name + strlen(LINK->cell_name), "/%s",
		root->UU.U1.c_d->name);
	if (*root->prefix != '\0')
	  sprintf(LINK->cell_name + strlen(LINK->cell_name), ".%s",
		  root->prefix);
	write_comp_ports_2(root->UU.U1.c_d->data, LINK);
	/*
	 tp2.x := root^.c_d^.ur.x;
	 tp2.y := root^.c_d^.ur.y;
	 write_port_list (root^.c_d^.portlist, tp2);
	    someday COMP cells will have ports too*/
      } else {
	tp2.x = root->UU.g_d->ur.x;
	tp2.y = root->UU.g_d->ur.y;
	sprintf(LINK->cell_name + strlen(LINK->cell_name), "/%s",
		root->UU.g_d->name);
	if (*root->prefix != '\0')
	  sprintf(LINK->cell_name + strlen(LINK->cell_name), ".%s",
		  root->prefix);
	write_port_list(root->UU.g_d->portlist, tp2, LINK);
      }

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


void write_comp_ports(void)
{
  struct LOC_write_comp_ports V;
  tr_matrix old_mat;
  Char base_name[17];   /* base portion of file name w/o '.CIF' */
  comp_list *o_sc;
  Char ans_str[fidleng + 1], ans2_str[fidleng + 1];
  Char STR1[81];
  Char STR2[182];
  Char STR3[178];
  Char STR4[128];

  V.portfile = NULL;
  gsave();
  xor_off();
  alpha_screen(CLR);
  m_alpha_on();
  m_graphics_off();
  pl_ident();   /* identity matrix */
  old_mat = tr_ctm;   /* Save it for later */

  getcellname(ans2_str, "Name of cell to write? ", "");
  do {
    if (*ans2_str == '\0' || strpos2(ans2_str, "-ABORT", 1) != 0)
      goto _L1;
    /* now search both comp lists for the cell name */
    o_sc = comp_cells;
    do {
      o_sc = o_sc->next;
    } while (o_sc != comp_cells && strcmp(o_sc->name, ans2_str));
    if (o_sc == comp_cells) {
      m_alpha_on();
      sprintf(STR3,
	      "Composition cell: \"%s\" not found.  Name of cell to write? ",
	      ans2_str);
      strcpy(ans2_str, getcellname(STR1, STR3, ""));
    }
  } while (o_sc == comp_cells);

  sprintf(STR4, "%s.PORTS", ans2_str);
  getfilename(ans_str, "\n\nName of output file? ", STR4);
  m_alpha_on();
  if (*ans_str == '\0' || strpos2(ans_str, "-ABORT", 1) != 0)
    goto _L1;

  /* format string to be read from */
  if (!dofixname(ans_str, base_name, ".PORTS"))
    goto _L1;

  TRY(try4);
    if (V.portfile != NULL)
      V.portfile = freopen(ans_str, "w", V.portfile);
    else
      V.portfile = fopen(ans_str, "w");
    if (V.portfile == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry4;
    }
  RECOVER2(try4,_Ltry4);
    show_error(ans_str, false);
    goto _L1;
  ENDTRY(try4);
  m_alpha_on();
  printf("\nWriting to file: %s\n", ans_str);

  TRY(try5);
    sprintf(V.cell_name, "/%s", ans2_str);
    write_comp_ports_2(o_sc->data, &V);
    if (V.portfile != NULL)
      fclose(V.portfile);
    V.portfile = NULL;
    printf("Ports of cell: \"%s\" written successfully to %s\n",
	   ans2_str, ans_str);
    /* Make sure top 2 lines are clear */
    printf("\001\t\n\t\001");

  RECOVER(try5);
    sprintf(STR2,
      "Error writing ports of cell \"%s\" in procedure WRITE_COMP_PORTS",
      ans2_str);
    show_error(STR2, false);
    if (V.portfile != NULL)
      fclose(V.portfile);
    V.portfile = NULL;
  ENDTRY(try5);
_L1:
  grestore();
  both_screens(ON, ON);
  if (V.portfile != NULL)
    fclose(V.portfile);
}


#define tablet          706



Static void play_music(void)
{
  FILE *infyle;
  Char fbox[256];
  Char STR1[92];
  Char *TEMP;

  infyle = NULL;
  TRY(try6);
    TRY(try7);
      nk_keybufclear();
      if (infyle != NULL) {
	sprintf(STR1, "%sMUSIC.TEXT", WolLib);
	infyle = freopen(STR1, "r", infyle);
      } else {
	sprintf(STR1, "%sMUSIC.TEXT", WolLib);
	infyle = fopen(STR1, "r");
      }
      if (infyle == NULL) {
	P_escapecode = -10;
	P_ioresult = FileNotFound;
	goto _Ltry7;
      }
      do {
	fgets(fbox, 256, infyle);
	TEMP = strchr(fbox, '\n');
	if (TEMP != NULL)
	  *TEMP = 0;
	P_writestringln(tablet, fbox);
      } while (!(nk_keybufsize() != 0 || P_eof(infyle)));
      nk_keybufclear();
    RECOVER2(try7,_Ltry7);
      ;
    ENDTRY(try7);
    if (infyle != NULL)
      fclose(infyle);
    infyle = NULL;
  RECOVER(try6);
    ;
  ENDTRY(try6);
  if (infyle != NULL)
    fclose(infyle);
}

#undef tablet


Static void write_port(port_node *p)
{
  fprintf(cif_fil, "86 Name %s\n", p->name);
  fprintf(cif_fil, "   Position %ld %ld   %ld %ld\n",
	  p->p1.x * 2, p->p1.y * 2, p->p2.x * 2, p->p2.y * 2);
  fprintf(cif_fil, "   Side %c\n", p->side);
  fprintf(cif_fil, "   Layer %.*s\n",
	  (int)(strlen(layers[p->layerno - min_layer].cif_name) - 1),
	  layers[p->layerno - min_layer].cif_name + 1);
  if (*p->signaltype != '\0')
    fprintf(cif_fil, "   Type %s\n", p->signaltype);
  if (p->width > 0)
    fprintf(cif_fil, "   Width %ld\n", p->width);
  fprintf(cif_fil, "   ;\n");
}


Static void w_cif_box(node *n)
{
  Char newname[11];
  port_node *ports;
  Char STR1[256], STR2[256];

  ports = n->portlist;   /* write out ports, if any */
  while (ports != NULL) {
    write_port(ports);
    ports = ports->next;
  }

  strcpy(newname, n->name);
  sprintf(STR1, "%.10s", "VDD");
  if (!strcmp(n->name, STR1))
    strcpy(newname, "VDD IAV");
  else {
    sprintf(STR2, "%.10s", "GND");
    if (!strcmp(n->name, STR2))
      strcpy(newname, "GND IAG");
  }

  if (*n->name != '\0')
    fprintf(cif_fil, "84 %ld %ld %s;\n",
	    n->ur.x + n->ll.x, n->ur.y + n->ll.y, newname);
  fprintf(cif_fil, "B %ld %ld %ld %ld;\n",
	  (n->ur.x - n->ll.x) * 2, (n->ur.y - n->ll.y) * 2, n->ur.x + n->ll.x,
	  n->ur.y + n->ll.y);
  if (!quiet_startup)   /* show that something is happening */
    putchar('.');
}


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

Static void writ_cif_cell(node *n)
{
  while (n != NULL) {
    if (n->layer == bb) {
      fprintf(cif_fil, "(MBB;\n");
      w_cif_box(n);
      fprintf(cif_fil, ");\n");
    } else {
      if (layers_on[n->layer - min_layer]) {
	if (n->layer != a_w_layer) {
	  fprintf(cif_fil, "%s;\n", layers[n->layer - min_layer].cif_name);
	  a_w_layer = n->layer;
	}
	w_cif_box(n);
      }
    }
    writ_cif_cell(n->child);
    n = n->next;
  }
}


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

Static void writ_geom_cell(cell *p)
{
  a_w_node *scan, *t;
  boolean t_fl;

  scan = a_w_list;
  t_fl = false;
  while (scan != NULL) {
    if (!strcmp(scan->name, p->name))
      t_fl = true;
    scan = scan->next;
  }
  if (t_fl != false)
    return;
  if (!quiet_startup)
    printf("Writing cell: %s\n", p->name);
  t = get_a_w_node();
  t->sym_num = a_w_count;
  a_w_count++;
  t->next = a_w_list;
  a_w_list = t;
  strcpy(t->name, p->name);
  fprintf(cif_fil, "DS ");
  fprintf(cif_fil, "%d", t->sym_num);
  fprintf(cif_fil, " %d 2 ;\n", lambda_to_microns);
  fprintf(cif_fil, "9 %s;\n", t->name);   /* GEG remove extra space */
  fprintf(cif_fil, "(MBB;\n");
  fprintf(cif_fil, "B ");
  fprintf(cif_fil, "%ld %ld %ld %ld",
	  p->ur.x * 2, p->ur.y * 2, p->ur.x, p->ur.y);
  fprintf(cif_fil, ";);\n");
  /* update last modified data, if necessary, and print it */
  if (p->modified) {
    p->revision_number++;
    get_date_string(p->revision_date);
  }
  /* writeln ('Writing cell revision: ', p^.revision_number:0);  */
  fprintf(cif_fil, "(Number of Revision :  %d ) ;\n", p->revision_number);
  fprintf(cif_fil, "(Date of Revision:  %s ) ;\n", p->revision_date);


  /* MAS - reset current layer info from one cell to the next */
  a_w_layer = 0;

  writ_cif_cell(p->data);
  fprintf(cif_fil, "DF;\n");
  if (!quiet_startup)
    putchar('\n');
  p->modified = false;   /* Just written to disk, GEG */
}


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

Static long get_ds_num(c_cell *n)
{
  a_w_node *a;
  boolean t_fl;

  a = a_w_list;
  t_fl = false;
  while (t_fl == false) {
    if (n->tag == COMP) {
      if (!strcmp(n->UU.U1.c_d->name, a->name))
	t_fl = true;
      else
	a = a->next;
    } else if (!strcmp(n->UU.g_d->name, a->name))
      t_fl = true;
    else
      a = a->next;
  }
  return (a->sym_num);
}


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

Static c_cell *xform_bbox(c_cell *cell_)
{
  c_cell *tmp;

  tmp = get_c_c_cell();
  switch (cell_->xform) {

  case 0:
    tmp->ll.x = 0;
    tmp->ll.y = 0;
    break;

  case 1:  /* rot by 90 */
    tmp->ll.x = cell_->ll.y - cell_->ur.y;
    tmp->ll.y = 0;
    break;

  case 2:  /* rot by 180 */
    tmp->ll.x = -cell_->ur.x;
    tmp->ll.y = -cell_->ur.y;
    break;

  case 3:  /* rot by 270 */
    tmp->ll.x = cell_->ll.x;
    tmp->ll.y = -cell_->ur.y;
    break;

  case 4:  /* M0 so do nothing*/
    tmp->ll.x = cell_->ll.x;
    tmp->ll.y = cell_->ll.y;
    break;

  case 5:  /* m90 */
    tmp->ll.x = -cell_->ur.x;
    tmp->ll.y = cell_->ll.y;
    break;

  case 6:  /* m180 - reflect in x-axis */
    tmp->ll.x = cell_->ll.x;
    tmp->ll.y = -cell_->ur.y;
    break;

  case 7:  /* M270 - so reflect in both x and y */
    tmp->ll.x = -cell_->ur.x;
    tmp->ll.y = -cell_->ur.y;
    break;
  }
  return tmp;
}


Static void writ_comp_cell(comp_list *p)
{
  a_w_node *t;
  c_cell *scan;
  long ds_num;
  boolean t_fl;
  routing *rt, *rt2;

  t = a_w_list;
  t_fl = false;
  while (t != NULL) {
    if (!strcmp(t->name, p->name))
      t_fl = true;
    t = t->next;
  }
  if (t_fl != false)
    return;
  if (!quiet_startup)
    printf("Writing cell: %s\n", p->name);
  t = get_a_w_node();
  t->sym_num = a_w_count;
  a_w_count++;
  t->next = a_w_list;
  a_w_list = t;
  strcpy(t->name, p->name);
  fprintf(cif_fil, "DS ");
  fprintf(cif_fil, "%d", t->sym_num);
  fprintf(cif_fil, " %d 2 ;\n", lambda_to_microns);
  fprintf(cif_fil, "9 %s;\n", t->name);
  fprintf(cif_fil, "(MBB;\n");
  fprintf(cif_fil, "B ");
  fprintf(cif_fil, "%ld %ld %ld %ld",
	  p->ur.x * 2, p->ur.y * 2, p->ur.x, p->ur.y);
  fprintf(cif_fil, ";);\n");
  /* update last modified data, if necessary, and print it */
  if (p->modified) {
    p->revision_number++;
    get_date_string(p->revision_date);
  }
  /* writeln ('Writing cell revision: ', p^.revision_number:0); */
  fprintf(cif_fil, "(Number of Revision:  %d ) ;\n", p->revision_number);
  fprintf(cif_fil, "(Date of Revision:  %s ) ;\n", p->revision_date);

  scan = p->data;
  while (scan != NULL) {
    fprintf(cif_fil, "85 %s;\n", scan->prefix);
    fprintf(cif_fil, "C ");
    ds_num = get_ds_num(scan);
    fprintf(cif_fil, "%ld", ds_num);
    switch (scan->xform) {

    case 1:
      fprintf(cif_fil, " R 0 1");
      break;

    case 2:
      fprintf(cif_fil, " R -1 0");
      break;

    case 3:
      fprintf(cif_fil, " R 0 -1");
      break;

    case 4:
      fprintf(cif_fil, " MX");
      break;

    case 5:
      fprintf(cif_fil, " MX R 0 1");
      break;

    case 6:
      fprintf(cif_fil, " MX R -1 0");
      break;

    case 7:
      fprintf(cif_fil, " MX R 0 -1");
      break;
    }

    fprintf(cif_fil, " T ");
    /*  WRONG  --  CIF translates corner to corner, not to center     MAS
             cen_x := (scan^.ll.x + scan^.ur.x);
             cen_y := (scan^.ll.y + scan^.ur.y);
             write(cif_fil, cen_x:0,' ',cen_y:0);
    */

    /*      temp_bbox := xform_bbox (scan);
          if not good_cif then temp_bbox^.ll := zero_point;
          write(cif_fil, (2*(scan^.ll.x-temp_bbox^.ll.x)):0,' ',
                         (2*(scan^.ll.y-temp_bbox^.ll.y)):0);
    */
    fprintf(cif_fil, "%ld %ld", scan->ll.x * 2, scan->ll.y * 2);
    fprintf(cif_fil, ";\n");
    scan = scan->next;
  }
  /* ALWAYS write out a prefix, to cancel previous prefixes */

  rt = p->routing_;
  a_w_layer = 0;
  while (rt != NULL) {
    rt2 = rt;
    if (rt->layer != a_w_layer) {
      fprintf(cif_fil, "%s;\n", layers[rt->layer - min_layer].cif_name);
      a_w_layer = rt->layer;
    }
    fprintf(cif_fil, "W %d %ld %ld",
	    rt->width * 2, rt->pt1.x * 2, rt->pt1.y * 2);
    while (rt2 != NULL) {
      fprintf(cif_fil, "\n    %ld %ld", rt2->pt2.x * 2, rt2->pt2.y * 2);
      rt2 = rt2->to_point;
    }
    fprintf(cif_fil, " ;\n");
    rt = rt->next;
  }

  fprintf(cif_fil, "DF;\n");
  p->modified = false;   /* Written to disk, not modified GEG */
}


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

Static void do_comp_cell(comp_list *p)
{
  c_cell *sc;

  sc = p->data;
  while (sc != NULL) {
    if (sc->tag == GEOM)
      writ_geom_cell(sc->UU.g_d);
    else
      do_comp_cell(sc->UU.U1.c_d);
    sc = sc->next;
  }
  writ_comp_cell(p);
}


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

void dump_all(void)
{
  /* dumps all the cells in memory, except for the two buffers */
  cell *g_cells;
  comp_list *c_cells;
  Char ans_str[fidleng + 1];   /* This is to be a file name */
  Char base_name[17];   /* base portion of file name w/o '.CIF' */

  a_w_list = NULL;
  a_w_layer = 0;
  a_w_count = initial_cif_symbol_number;

  alpha_screen(CLR);
  getfilename(ans_str, "Name of output file? ", "dump.cif");
  if (*ans_str == '\0' || strpos2(ans_str, "-ABORT", 1) != 0)
    goto _L1;

  /* format string to be read from */
  if (!dofixname(ans_str, base_name, ".cif"))
    goto _L1;

  if (!OK_write_file(ans_str, base_name))
    goto _L1;

  TRY(try8);
    if (cif_fil != NULL)
      cif_fil = freopen(ans_str, "w", cif_fil);
    else
      cif_fil = fopen(ans_str, "w");
    if (cif_fil == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry8;
    }
  RECOVER2(try8,_Ltry8);

    show_error(ans_str, false);
    goto _L1;
  ENDTRY(try8);
  TRY(try9);
    alpha_screen(CLR);
    m_alpha_on();
    g_cells = geom_cells;
    do {
      if (g_cells != geom_cells)
	writ_geom_cell(g_cells);
      g_cells = g_cells->next;
    } while (g_cells != geom_cells);

    c_cells = comp_cells;
    do {
      if (c_cells != comp_cells)
	do_comp_cell(c_cells);
      c_cells = c_cells->next;
    } while (c_cells != comp_cells);

    fprintf(cif_fil, "C %d T 0 0;\n", a_w_count - 1);
    fprintf(cif_fil, "E\n");   /* no semicolon after E */
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;
    printf("\nDump written successfully to %s\n", ans_str);
    /* Make sure top 2 lines are clear */
    printf("\001\t\n\t\001");
  RECOVER(try9);
    show_error("Something horrible happened in DUMP_ALL", false);
    TRY(try10);
      if (cif_fil != NULL)
	fclose(cif_fil);
      cif_fil = NULL;
    RECOVER(try10);
      ;
    ENDTRY(try10);
  ENDTRY(try9);
_L1:
  m_graphics_on();
  m_alpha_on();
}


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

void write_cif(void)
{
  Char ans_str[fidleng + 1];   /* This is to be a file name */
  Char ans2_str[81];
  cell *scan;
  comp_list *o_sc;
  Char base_name[17];   /* base portion of file name w/o '.CIF' */
  Char vol[fidleng + 1], path[fidleng + 1];
  Char STR1[81];
  Char STR3[126];
  Char STR4[86];

  a_w_list = NULL;
  alpha_screen(CLR);
  m_alpha_on();
  m_graphics_off();

  getcellname(ans2_str, "Name of cell to write? ", "");
  do {
    if (*ans2_str == '\0' || strpos2(ans2_str, "-ABORT", 1) != 0)
      goto _L1;
    /* now search both geom and comp lists for the cell name */
    o_sc = comp_cells;
    do {
      o_sc = o_sc->next;
    } while (o_sc != comp_cells && strcmp(o_sc->name, ans2_str));
    scan = geom_cells;
    do {
      scan = scan->next;
    } while (scan != geom_cells && strcmp(scan->name, ans2_str));
    if (scan == geom_cells && o_sc == comp_cells) {
      m_alpha_on();
      sprintf(STR3, "Cell: \"%s\" not found.  Name of cell to write? ",
	      ans2_str);
      strcpy(ans2_str, getcellname(STR1, STR3, ""));
    }
  } while (scan == geom_cells && o_sc == comp_cells);

  sprintf(STR4, "%s.cif", ans2_str);
  getfilename(ans_str, "\n\nName of output file? ", STR4);
  m_alpha_on();
  if (*ans_str == '\0' || strpos2(ans_str, "-ABORT", 1) != 0)
    goto _L1;

  /* format string to be read from */
  if (!dofixname(ans_str, base_name, ".cif"))
    goto _L1;

  if (!OK_write_file(ans_str, base_name))
    goto _L1;

  TRY(try11);
    if (cif_fil != NULL)
      cif_fil = freopen(ans_str, "w", cif_fil);
    else
      cif_fil = fopen(ans_str, "w");
    if (cif_fil == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry11;
    }
  RECOVER2(try11,_Ltry11);
    show_error(ans_str, false);
    goto _L1;
  ENDTRY(try11);
  a_w_list = NULL;
  a_w_layer = 0;
  a_w_count = initial_cif_symbol_number;

  TRY(try12);
    m_alpha_on();
    printf("\nWriting to file: %s\n", ans_str);
    if (!fp_getwd(path, vol))
      *path = '\0';
    else
      strcat(path, "/");

    fprintf(cif_fil, "( WOL CIF in file %s%s created by %s on %s );\n",
	    path, ans_str, wol_username, get_date_string(STR1));
    if (o_sc != comp_cells)
      do_comp_cell(o_sc);
    else
      writ_geom_cell(scan);
    fprintf(cif_fil, "C %d T 0 0;\n", a_w_count - 1);
    fprintf(cif_fil, "E\n");   /* no semicolon after E */
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;
    printf("\nCell: \"%s\" written successfully to %s\n", ans2_str, ans_str);
    /* Make sure top 2 lines are clear */
    printf("\001\t\n\t\001");

  RECOVER(try12);
    sprintf(STR3, "Error writing cell \"%s\" in procedure WRITE_CIF",
	    ans2_str);
    show_error(STR3, false);
    /*writeln('Trying to restore original file: ',ans_str);*/
    /*###??? This won't restore original file!!!  Need something more. */
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;
  ENDTRY(try12);
_L1:
  recl_a_w_node(&a_w_list);
  both_screens(ON, ON);
}


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


void write_cif_file(Char *ans_str_, Char *cell_name_)
{
  Char ans_str[fidleng + 1], cell_name[fidleng + 1];

  boolean file_exists;
  cell *scan;
  comp_list *o_sc;
  Char base_name[17];   /* base portion of file name w/o '.CIF' */
  Char vol[fidleng + 1], path[fidleng + 1];
  Char STR1[166];
  Char STR3[81];

  strcpy(ans_str, ans_str_);
  strcpy(cell_name, cell_name_);
  a_w_list = NULL;
  m_alpha_on();
  do {
    if (*cell_name == '\0')
      goto _L1;
    /* now search both geom and comp lists for the cell name */
    o_sc = comp_cells;
    do {
      o_sc = o_sc->next;
    } while (o_sc != comp_cells && strcmp(o_sc->name, cell_name));
    scan = geom_cells;
    do {
      scan = scan->next;
    } while (scan != geom_cells && strcmp(scan->name, cell_name));
    if (scan == geom_cells && o_sc == comp_cells) {
      printf("Cell: \"%s\" not found.\n", cell_name);
      goto _L1;
    }
  } while (scan == geom_cells && o_sc == comp_cells);

  if (*ans_str == '\0')
    goto _L1;

  /* format string to be read from */
  if (!dofixname(ans_str, base_name, ".cif"))
    goto _L1;

  if (!OK_write_file(ans_str, base_name))
    goto _L1;

  TRY(try13);
    if (cif_fil != NULL)
      cif_fil = freopen(ans_str, "w", cif_fil);
    else
      cif_fil = fopen(ans_str, "w");
    if (cif_fil == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry13;
    }
  RECOVER2(try13,_Ltry13);
    show_error(ans_str, false);
    goto _L1;
  ENDTRY(try13);
  a_w_list = NULL;
  a_w_layer = 0;
  a_w_count = initial_cif_symbol_number;

  TRY(try14);
    m_alpha_on();
    printf("\nWriting to file: %s\n", ans_str);
    if (!fp_getwd(path, vol))
      *path = '\0';
    else
      strcat(path, "/");

    fprintf(cif_fil, "( WOL CIF in file %s%s created by %s on %s );\n",
	    path, ans_str, wol_username, get_date_string(STR3));
    if (o_sc != comp_cells)
      do_comp_cell(o_sc);
    else
      writ_geom_cell(scan);
    fprintf(cif_fil, "C %d T 0 0;\n", a_w_count - 1);
    fprintf(cif_fil, "E\n");   /* no semicolon after E */
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;
    printf("\nCell: \"%s\" written successfully to %s\n", cell_name, ans_str);
    /* Make sure top 2 lines are clear */
    printf("\001\t\n\t\001");

  RECOVER(try14);
    sprintf(STR1, "Error writing cell \"%s\" in procedure WRITE_CIF",
	    cell_name);
    show_error(STR1, false);
    /*writeln('Trying to restore original file: ',ans_str);*/
    /*###??? This won't restore original file!!!  Need something more. */
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;
  ENDTRY(try14);
_L1:
  recl_a_w_node(&a_w_list);
  both_screens(ON, ON);
}


void dump_cells_independently(boolean all_geom_cells, boolean all_comp_cells)
{
  cell *geom_scan;
  comp_list *comp_scan;

  geom_scan = geom_cells;
  do {
    if ((all_geom_cells || geom_scan->modified) &&
	strcmp(geom_scan->name, "*GEOM*")) {
      alpha_screen(CLR);
      write_cif_file(geom_scan->name, geom_scan->name);
    }
    geom_scan = geom_scan->next;
  } while (geom_scan != geom_cells);

  comp_scan = comp_cells;
  do {
    if ((all_comp_cells || comp_scan->modified) &&
	strcmp(comp_scan->name, "*COMP*")) {
      alpha_screen(CLR);
      write_cif_file(comp_scan->name, comp_scan->name);
    }
    comp_scan = comp_scan->next;
  } while (comp_scan != comp_cells);
  alpha_screen(CLR);
  alpha_screen(OFF);
}


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

Static void get_comment(void)
{
  Char r_c;

  do {
    r_c = getc(cif_fil);
    if (r_c == '\n')
      r_c = ' ';
    if (r_c == C_LPAREN)
      get_comment();
  } while (r_c != C_RPAREN);
}


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

Static void get_semi(void)
{
  /* Gets chars until the next semi    */
  Char r_c;

  do {
    r_c = getc(cif_fil);
    if (r_c == '\n')
      r_c = ' ';
    if (r_c == C_LPAREN)
      get_comment();
  } while (r_c != C_SEMI);
}


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

Static void begin_cell(void)
{
  a_w_node *t_p;

  *d_cell_name = '\0';
  last_revision_number = 0;
  *last_revision_date = '\0';
  d_cell_ll.x = 0;
  d_cell_ll.y = 0;
  d_cell_ur.x = 0;
  d_cell_ur.y = 0;
  t_p = get_a_w_node();
  t_p->next = a_w_list;
  a_w_list = t_p;
  defining_cell = true;
  d_set_bb = false;
  d_cif_layer = 1;
  main_ = NULL;
  d_c_p = NULL;
}


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

Static void cif_c_name(void)
{
  Char c;   /* Dummy */

  c = getc(cif_fil);   /*####What is this dummy character? */
  if (c == '\n')
    c = ' ';
  c = getc(cif_fil);
  if (c == '\n')
    c = ' ';
  while (c == ' ') {   /* skip spaces at beginning of names. */
    c = getc(cif_fil);
    if (c == '\n')
      c = ' ';
  }
  d_cell_name[0] = '\0';
  while (c != ';' && c != ' ') {
    strcat(d_cell_name, " ");
    d_cell_name[strlen(d_cell_name) - 1] = c;
    c = getc(cif_fil);
    if (c == '\n')
      c = ' ';
  }
  if (c == ' ')
    get_semi();
}


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

Static void cif_box(void)
{
  double cx, cy, l, w;
  long tmp1, tmp2;
  point tp1, tp2;

  if (defining_cell == false)
    begin_cell();
  fscanf(cif_fil, "%lg%lg%lg%lg", &l, &w, &cx, &cy);
  tmp1 = (long)floor(cx / cell_scale - l / cell_scale / 2 + 0.5);
  tmp2 = (long)floor(cy / cell_scale - w / cell_scale / 2 + 0.5);
  tp1 = change_to_point(tmp1, tmp2);
  tmp1 = (long)floor(cx / cell_scale + l / cell_scale / 2 + 0.5);
  tmp2 = (long)floor(cy / cell_scale + w / cell_scale / 2 + 0.5);
  tp2 = change_to_point(tmp1, tmp2);
  if (cif_prefix_found) {   /* no name */
    fast_add(tp1, tp2, d_cif_layer, cif_prefix_name, building_ports);
    cif_prefix_found = false;
  } else
    fast_add(tp1, tp2, d_cif_layer, "", building_ports);
  building_ports = NULL;
  get_semi();
  if (!quiet_startup)   /* MAS  --  show that something is happening */
    putchar('.');
}


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

Static void cif_poly(void)
{
  point tp1, tp2, tp3;

  if (defining_cell == false)
    begin_cell();
  fscanf(cif_fil, "%ld%ld%ld%ld%ld%ld", &tp1.x, &tp1.y, &tp2.x, &tp2.y,
	 &tp3.x, &tp3.y);
  if (cif_prefix_found) {   /* no name */
    fast_add(tp1, tp3, d_cif_layer, cif_prefix_name, building_ports);
    cif_prefix_found = false;
  } else
    fast_add(tp1, tp3, d_cif_layer, "", building_ports);
  get_semi();
  if (!quiet_startup)   /* MAS  --  show that something is happening */
    putchar('.');
}


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

Static void cif_wire(void)
{
  /* reads a wire, and pre-pends it to d_c_p^.routing */
  point tp1, tp2;
  routing *rt, *rt2, *rt3;
  Char s[81];
  long width_of_wire, junk;
  Char *TEMP;

  if (d_c_p == NULL) {
    d_c_p = get_c_cell();
    d_c_p->modified = false;   /* Just read from disk, GEG */
    strcpy(d_c_p->name, d_cell_name);
    d_c_p->ll = d_cell_ll;
    d_c_p->ur = d_cell_ur;
    d_c_p->data = NULL;
    d_c_p->routing_ = NULL;
  }
  fscanf(cif_fil, "%ld", &width_of_wire);
  width_of_wire /= 2;
  rt = d_c_p->routing_;
  rt2 = rt;
  fgets(s, 81, cif_fil);
  TEMP = strchr(s, '\n');
  if (TEMP != NULL)
    *TEMP = 0;
  sscanf(s, "%ld%ld%ln", &tp1.x, &tp1.y, &junk);
  junk++;   /* get first point */
  tp1.x /= 2;
  tp1.y /= 2;
  do {
    fgets(s, 81, cif_fil);
    TEMP = strchr(s, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    TRY(try15);
      sscanf(s, "%ld%ld%ln", &tp2.x, &tp2.y, &junk);
      junk++;   /* get next point */
      tp2.x /= 2;
      tp2.y /= 2;
      rt3 = get_routing_node();
      rt3->pt1 = tp1;
      rt3->pt2 = tp2;
      rt3->layer = d_cif_layer;
      rt3->width = width_of_wire;
      if (cif_prefix_found)
	strcpy(rt3->name, cif_prefix_name);
      tp1 = tp2;   /* save old point */
      if (rt != d_c_p->routing_) {   /* allow sems on their own line */
	rt->to_point = rt3;
	rt = rt3;
      } else {
	rt = rt3;   /*just point to next site to append */
	rt2 = rt3;   /* keep pointer to head */
      }
    RECOVER(try15);
      if (strpos2(s, ";", 1) == 0)
	_Escape(P_escapecode);
    ENDTRY(try15);
  } while (strpos2(s, ";", 1) == 0);
  /* now insert at head of d_c_p^.routing */
  rt2->next = d_c_p->routing_;
  d_c_p->routing_ = rt2;
  cif_prefix_found = false;
  if (!quiet_startup)   /* MAS  --  show that something is happening */
    putchar('.');
}


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

Static void cif_layer(void)
{
  short count;
  Char t_s[5];
  Char c;
  Char STR1[26];

  d_cif_layer = 0;
  *t_s = '\0';
  c = 'L';
  while (c != ';') {
    strcat(t_s, " ");
    t_s[strlen(t_s) - 1] = c;
    c = getc(cif_fil);
    if (c == '\n')
      c = ' ';
  }
  count = 1;
  while (count < 17 && d_cif_layer == 0) {
    if (!strcmp(layers[count - min_layer].cif_name, t_s))
      d_cif_layer = count;
    count++;
  }
  if (d_cif_layer == 0) {
    sprintf(STR1, "Illegal layer name: %s", t_s);
    show_message(STR1, false);
    _Escape(10);
  }
}


/*$if false$  Recursion is EVIL
     PROCEDURE get_ports (pt : node_ptr; var list : port_ptr);
        { pt points to tree from which a linear port list will be extracted }
        { list points to the head of the returned list }
        { this code is EXACTLY the same as in file WOLMAIN }
          var port2, port3 : port_ptr;
        begin
           if pt <> NIL then
             begin
                get_ports (pt^.next, list);
                port2 := pt^.portlist;
                while port2 <> nil do
                  begin
                    port3 := get_port_node;
                    port3^ := port2^;
                    port3^.next := list;
                    list := port3;
                    port2 := port2^.next;
                  end;
                get_ports (pt^.child, list);
             end;
         end;
$end$*/

Local 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 */
  /* this code is EXACTLY the same as in file WOLMAIN */
  /* No it's not; there is no evil tail recursion! */
  port_node *port2, *port3;

  while (pt != NULL) {
    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);
    pt = pt->next;
  }
}


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

Static void close_cif_cell(void)
{
  cell *t_cell;
  comp_list *t_sc, *t_op;
  cell *scan;
  long p;   /* for strwrite */
  Char STR1[126];
  Char STR2[122];
  Char *TEMP;


  if (!defining_cell) {
    show_message("Error:  DF found with no DS.", false);
    _Escape(10);
  }
  if (*d_cell_name == '\0') {
    m_alpha_on();
    printf("\nCell defined with no name.  Name [CELL%d]? ", a_w_list->sym_num);
    fgets(d_cell_name, 81, stdin);
    TEMP = strchr(d_cell_name, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    if (*d_cell_name == '\0') {
      sprintf(d_cell_name, "CELL%d", a_w_list->sym_num);
      p = strlen(d_cell_name) + 1;
    }
  }
  if (d_c_p == NULL && !quiet_startup)   /* only for geometry cells */
    putchar('\n');
  printf("Cell %s defined #%d\n", d_cell_name, a_w_list->sym_num);
  strcpy(a_w_list->name, d_cell_name);
  if (d_c_p == NULL) {  /* it is a geometry cell */
    /* need to ERASE previous definition, if any */
    scan = geom_cells;
    do {
      scan = scan->next;
    } while (strcmp(scan->name, d_cell_name) && scan != geom_cells);
    if (scan != geom_cells) {  /* it exists, so erase it */
      sprintf(STR2, "\007WARNING: cif name collision on cell \"%s\"",
	      d_cell_name);
      show_message(STR2, false);
      printf("Old cell overwritten--Complain to Mass.\n");
      scan->prev->next = scan->next;
      scan->next->prev = scan->prev;
      printf("Recl_nodes\n");
      recl_nodes(&scan->data);
      printf("Recl_g_cell\n");
      recl_g_cell(&scan);
    }

    t_cell = get_g_cell();
    strcpy(t_cell->name, d_cell_name);
    t_cell->next = geom_cells->next;
    t_cell->prev = geom_cells;
    t_cell->modified = false;   /* Just read from disk, GEG */
    t_cell->revision_number = last_revision_number;
    strcpy(t_cell->revision_date, last_revision_date);
    geom_cells->next = t_cell;
    t_cell->next->prev = t_cell;
    t_cell->data = main_;
    /* get ports, and write into cell definition */
    get_ports(main_, &t_cell->portlist);
    if (d_set_bb == false) {
      set_bb(t_cell);   /* make and normalize MBB */
      inc_nodes(t_cell->data, -t_cell->ll.x, -t_cell->ll.y);
      t_cell->ur.x -= t_cell->ll.x;
      t_cell->ur.y -= t_cell->ll.y;
      t_cell->ll.x = 0;
      t_cell->ll.y = 0;
    } else {
      t_cell->ll = d_cell_ll;
      t_cell->ur = d_cell_ur;
    }
  } else {  /* it is a composition cell */
    recl_nodes(&main_);
    /* need to erase previously defined cell, if any */

    /* GEG-attempt to fix composition default name bug */
    strcpy(d_c_p->name, d_cell_name);
    strcpy(d_c_p->revision_date, last_revision_date);
    d_c_p->revision_number = last_revision_number;
    t_sc = comp_cells;
    while (t_sc->next != comp_cells && strcmp(t_sc->next->name, d_c_p->name))
      t_sc = t_sc->next;
    if (t_sc->next != comp_cells)
    {  /* cell is already defined, so must erase it */
      sprintf(STR1, "\007WARNING: cif comp name collision on cell \"%s\"",
	      d_c_p->name);
      show_message(STR1, false);
      printf("Old cell overwritten--Complain to Mass.\n");
      t_op = t_sc->next;
      t_sc->next = t_op->next;
      printf("Recl_c_cell\n");
      recl_c_cell(&t_op);
    }

    d_c_p->next = comp_cells->next;
    comp_cells->next = d_c_p;
    set_c_bb(d_c_p);
  }
  defining_cell = false;
  get_semi();
}


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

Static void cif_define(void)
{
  Char r_c;
  long dummy;

  r_c = getc(cif_fil);
  if (r_c == '\n')
    r_c = ' ';
  if (r_c == 'S') {
    if (defining_cell) {
      show_message("Error:  Cells definitions nested.", false);
      _Escape(10);
    }
    begin_cell();
    fscanf(cif_fil, "%hd%ld%hd", &a_w_list->sym_num, &dummy, &cell_scale);
    if (dummy != lambda_to_microns) {
      lambda_to_microns = dummy;
/* p2c: wol_cif.text, line 1375: Note: Character >= 128 encountered [281] */
/* p2c: wol_cif.text, line 1375: Note: Character >= 128 encountered [281] */
/* p2c: wol_cif.text, line 1375:
 * Note: WRITE statement contains color/attribute characters [203] */
      printf("\213\007\007\007\007WARNING: LAMBDA changed to %0.2f microns.\210\n",
	     dummy / 100.0);
      if (!strcmp(m_machine, "9836C"))
	play_music();
    }
    get_semi();
    return;
  }
  if (r_c == 'F')
    close_cif_cell();
  else
    get_semi();
}


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

Static Char get_x_rot(void)
{
  Char r_c;

  do {
    r_c = getc(cif_fil);
    if (r_c == '\n')
      r_c = ' ';
  } while (r_c != 'M' && r_c != 'R' && r_c != 'T');
  return r_c;
}


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

Static void cif_call(void)
{
  c_cell *t_p;
  cell *t_g;
  comp_list *t_c;
  a_w_node *t_a;
  Char t_nam[81];
  Char r_c;
  long s_num, x_r, y_r, h_x, h_y;

  if (!defining_cell) {
    get_semi();
    return;
  }
  if (d_c_p == NULL) {
    d_c_p = get_c_cell();
    d_c_p->modified = false;   /* Just read from disk, GEG */
    strcpy(d_c_p->name, d_cell_name);
    d_c_p->ll = d_cell_ll;
    d_c_p->ur = d_cell_ur;
    d_c_p->data = NULL;
    d_c_p->routing_ = NULL;
  }
  fscanf(cif_fil, "%ld", &s_num);
  t_a = a_w_list;
  while (t_a->sym_num != s_num)
    t_a = t_a->next;
  strcpy(t_nam, t_a->name);

  t_g = geom_cells;
  do {
    t_g = t_g->next;
  } while (t_g != geom_cells && strcmp(t_nam, t_g->name));
  if (t_g == geom_cells) {
    t_c = comp_cells;
    do {
      t_c = t_c->next;
    } while (strcmp(t_c->name, t_nam));
  }
  t_p = get_c_c_cell();
  if (cif_prefix_found) {
    strcpy(t_p->prefix, cif_prefix_name);
    cif_prefix_found = false;
  }
  t_p->next = d_c_p->data;
  d_c_p->data = t_p;
  t_p->xform = 0;
  if (t_g == geom_cells) {   /* then it is a call to another comp cell */
    t_p->tag = COMP;
    t_p->UU.U1.c_d = t_c;
    t_p->UU.U1.old_c_d = t_c;
    t_p->ll = t_c->ll;
    t_p->ur = t_c->ur;
  } else {
    t_p->tag = GEOM;
    t_p->UU.g_d = t_g;
    t_p->ll = t_g->ll;
    t_p->ur = t_g->ur;
  }
  do {
    r_c = get_x_rot();
    if (r_c == 'M')
      t_p->xform = 4;
    else if (r_c == 'R') {
      fscanf(cif_fil, "%ld%ld", &x_r, &y_r);
      if (x_r == 0) {
	if (y_r == 1)
	  t_p->xform++;
	else
	  t_p->xform += 3;
      } else if (y_r == 0)
	t_p->xform += 2;
    } else
      fscanf(cif_fil, "%ld%ld", &x_r, &y_r);
  } while (r_c != 'T');


  h_x = t_p->ur.x - t_p->ll.x;   /* MAS  */
  h_y = t_p->ur.y - t_p->ll.y;
  t_p->ll.x = x_r / cell_scale;
  t_p->ll.y = y_r / cell_scale;
  t_p->ur.x = x_r / cell_scale + h_x;
  t_p->ur.y = y_r / cell_scale + h_y;

  get_semi();
}


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

Static void cif_comment(void)
{
  Char t_st3[4];
  Char t_cs;
  long t_l;
  double l, w, xc, yc;
  long d1, d2, d3, d4;
  Char STR1[256], STR3[256];

  *t_st3 = '\0';
  fscanf(cif_fil, "%3[^\n]", t_st3);
  if (!strcmp(t_st3, "MBB")) {
    t_cs = getc(cif_fil);
    if (t_cs == '\n')
      t_cs = ' ';
    if (t_cs != ';') {
      get_semi();
      get_semi();
      do {
	t_cs = getc(cif_fil);
	if (t_cs == '\n')
	  t_cs = ' ';
      } while (t_cs != ';');
    }
    do {
      t_cs = getc(cif_fil);
      if (t_cs == '\n')
	t_cs = ' ';
    } while (t_cs != 'B' && t_cs != 'P');
    if (!d_set_bb) {
      if (!defining_cell)
	begin_cell();
      d_set_bb = true;
      if (t_cs == 'P')
	fscanf(cif_fil, "%ld%ld%ld%ld%ld%ld%ld%ld", &d_cell_ll.x,
	       &d_cell_ll.y, &d1, &d2, &d_cell_ur.x, &d_cell_ur.y, &d3, &d4);
      else {
	fscanf(cif_fil, "%lg%lg%lg%lg", &l, &w, &xc, &yc);
	d_cell_ll.x = (long)floor(xc / cell_scale - l / cell_scale / 2 + 0.5);
	d_cell_ll.y = (long)floor(yc / cell_scale - w / cell_scale / 2 + 0.5);
	d_cell_ur.x = (long)floor(xc / cell_scale + l / cell_scale / 2 + 0.5);
	d_cell_ur.y = (long)floor(yc / cell_scale + w / cell_scale / 2 + 0.5);
      }
    } else {
      t_l = d_cif_layer;
      d_cif_layer = bb;
      if (t_cs == 'B')
	cif_box();
      else
	cif_poly();
      d_cif_layer = t_l;
    }
    get_comment();
    get_semi();
    return;
  }
  if (!strcmp(t_st3, "Dat")) {
    do {
      t_cs = getc(cif_fil);
      if (t_cs == '\n')
	t_cs = ' ';
    } while (t_cs != ':');
    t_cs = getc(cif_fil);   /* eat two spaces */
    if (t_cs == '\n')
      t_cs = ' ';
    t_cs = getc(cif_fil);
    if (t_cs == '\n')
      t_cs = ' ';
    *last_revision_date = '\0';
    fscanf(cif_fil, "%80[^\n]", last_revision_date);
    sprintf(STR3, "%.*s",
	    strpos2(last_revision_date, ") ;", 1) - 1, last_revision_date);
    /* strip off trailing ') ;'  */
    strcpy(last_revision_date, strrtrim(strcpy(STR1, strltrim(STR3))));
    if (!quiet_startup)
      printf("Found revision date: %s\n", last_revision_date);
    /* no need to do a get_comment; get_semi; here -- we already have it */
    return;
  }
  if (strcmp(t_st3, "Num")) {
    get_comment();
    get_semi();
    return;
  }
  do {
    t_cs = getc(cif_fil);
    if (t_cs == '\n')
      t_cs = ' ';
  } while (t_cs != ':');
  fscanf(cif_fil, "%hd", &last_revision_number);
  if (!quiet_startup)
    printf("Found revision number: %12d\n", last_revision_number);
  get_comment();
  get_semi();

  /* not a magic comment, so just slurp it up */
}


#define max_chars_in_name  10


Local void get_cif_prefix(void)
{
  Char first_c[2];
  long chars_in_name;
  Char STR2[256];

  *cif_prefix_name = '\0';
  do {
    *first_c = '\0';
    fscanf(cif_fil, "%1[^\n]", first_c);
  } while (first_c[0] == ' ');
  chars_in_name = 0;
  if (first_c[0] != ';') {
    do {
      if (chars_in_name < max_chars_in_name) {  /* do not overflow string */
	sprintf(cif_prefix_name + strlen(cif_prefix_name), "%c", first_c);
	chars_in_name++;
      } else
	printf("Name too long: truncated  -- \"%c\" lost.\n", first_c);
      *first_c = '\0';
      fscanf(cif_fil, "%1[^\n]", first_c);
    } while (first_c[0] != ';');
  }
  cif_prefix_found = (*cif_prefix_name != '\0');
  strcpy(cif_prefix_name, strrtrim(strcpy(STR2, cif_prefix_name)));
      /* eat trailing blanks */
  /* eat special IAV and IAG on VDD and GND nodes. These will
     be re-appended before the CIF is written out */
  if (!strcmp(cif_prefix_name, "VDD IAV"))
    strcpy(cif_prefix_name, "VDD");
  else if (!strcmp(cif_prefix_name, "GND IAG"))
    strcpy(cif_prefix_name, "GND");
}

#undef max_chars_in_name

Local void get_port_info(port_node **p)
{
  Char first_c[2];
  Char tmp_str[81];
  Char ch;
  boolean done;
  long count;
  Char *TEMP;
  Char STR1[256];

  *p = get_port_node();
  (*p)->width = 0;
  *(*p)->signaltype = '\0';
  done = false;
  do {
    do {
      *first_c = '\0';
      fscanf(cif_fil, "%1[^\n]", first_c);
    } while (first_c[0] == ' ');
    ch = first_c[0];
    if (ch != ';') {
      do {
	*first_c = '\0';
	fscanf(cif_fil, "%1[^\n]", first_c);
      } while (first_c[0] != ' ');   /* eat up keyword */
    }
    switch (ch) {

    case 'N':
      do {
	*first_c = '\0';
	fscanf(cif_fil, "%1[^\n]", first_c);
      } while (first_c[0] == ' ');
      fgets(tmp_str, 81, cif_fil);
      TEMP = strchr(tmp_str, '\n');
      if (TEMP != NULL)
	*TEMP = 0;
      strcpy(tmp_str, strrtrim(strcpy(STR1, tmp_str)));
      sprintf((*p)->name, "%c%s", first_c, tmp_str);
      /* writeln ('found name = ', p^.name);       */
      break;

    case 'P':
      fscanf(cif_fil, "%ld%ld%ld%ld", &(*p)->p1.x, &(*p)->p1.y, &(*p)->p2.x,
	     &(*p)->p2.y);
      (*p)->p1.x /= 2;
      (*p)->p1.y /= 2;
      (*p)->p2.x /= 2;
      (*p)->p2.y /= 2;
      fscanf(cif_fil, "%*[^\n]");
      /* writeln ('found position');   */
      getc(cif_fil);
      break;

    case 'S':
      do {
	*first_c = '\0';
	fscanf(cif_fil, "%1[^\n]", first_c);
      } while (first_c[0] == ' ');
      (*p)->side = first_c[0];
      fscanf(cif_fil, "%*[^\n]");
      /* writeln ('Found side = ',p^.side); */
      getc(cif_fil);
      break;

    case 'L':
      do {
	*first_c = '\0';
	fscanf(cif_fil, "%1[^\n]", first_c);
      } while (first_c[0] == ' ');
      fgets(tmp_str, 81, cif_fil);
      TEMP = strchr(tmp_str, '\n');
      if (TEMP != NULL)
	*TEMP = 0;
      strcpy(tmp_str, strrtrim(strcpy(STR1, tmp_str)));
      sprintf((*p)->layer, "%c%s", first_c, tmp_str);
      /* now find wol layer number */
      count = 1;
      (*p)->layerno = 0;
      while (count < 17 && (*p)->layerno == 0) {
	sprintf(STR1, "%.*s",
		(int)(strlen(layers[count - min_layer].cif_name) - 1),
		layers[count - min_layer].cif_name + 1);
	if (!strcmp(STR1, (*p)->layer))
	  (*p)->layerno = count;
	count++;
      }
      /* writeln ('found layer = ',p^.layer,' = number ',p^.layerno:0); */
      break;

    case 'T':
      do {
	*first_c = '\0';
	fscanf(cif_fil, "%1[^\n]", first_c);
      } while (first_c[0] == ' ');
      fgets(tmp_str, 81, cif_fil);
      TEMP = strchr(tmp_str, '\n');
      if (TEMP != NULL)
	*TEMP = 0;
      strcpy(tmp_str, strrtrim(strcpy(STR1, tmp_str)));
      sprintf((*p)->signaltype, "%c%s", first_c, tmp_str);
      /* writeln ('found type = ',p^.signaltype);  */
      break;

    case 'W':
      fscanf(cif_fil, "%ld", &(*p)->width);
      fscanf(cif_fil, "%*[^\n]");
      /* writeln ('found width = ',p^.width);  */
      getc(cif_fil);
      break;

    case ';':
      done = true;
      fscanf(cif_fil, "%*[^\n]");
      /* writeln ('found semi; all done');   */
      getc(cif_fil);
      break;
    }/*case */
  } while (!done);
}


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

Static void cif_prefix(void)
{
  /* if the 84 extension is found, read x and y coords, and elecnode name;
     if the 85 extension is found, read the prefix for the called cell.
In both cases, the 8x extension PRECEEDs the object it modifies.
A global flag: cif_prefix_found is set to true in this routine,
and must be reset by the routine that reads the next line
  */
  Char first_c[2];
  long dummy;
  port_node *ports;

  *cif_prefix_name = '\0';
  *first_c = '\0';
  fscanf(cif_fil, "%1[^\n]", first_c);
  switch (first_c[0]) {

  case '4':
    fscanf(cif_fil, "%ld", &dummy);   /* discard the x and y coords */
    fscanf(cif_fil, "%ld", &dummy);   /* since we assume box is to follow */
    get_cif_prefix();
    break;

  case '5':
    get_cif_prefix();
    break;

  case '6':
    if (d_c_p == NULL) {   /* we are defining a geometry cell */
      get_port_info(&ports);
      ports->next = building_ports;
      building_ports = ports;
    }
    break;
  }
}


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

Static void cif_end(void)
{
  if (defining_cell)
    close_cif_cell();
}


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

Static void read_c_file(void)
{
  Char first_c;

  first_c = 'A';
  while (!P_eof(cif_fil) && first_c != 'E') {
    first_c = getc(cif_fil);
    if (first_c == '\n')
      first_c = ' ';
    switch (first_c) {

    case C_BOX:   /* B */
      cif_box();
      break;

    case C_POLY:   /* P */
      cif_poly();
      break;

    case C_LAYER:   /* L */
      cif_layer();
      break;

    case C_DEF:   /* D */
      cif_define();
      break;

    case C_CALL:   /* C */
      cif_call();
      break;

    case C_LPAREN:   /* ( */
      cif_comment();
      break;

    case C_CR:
      /* blank case */
      break;

    case C_NAME:   /* 9 */
      cif_c_name();
      break;

    case C_PREFIX:   /* 8 */
      cif_prefix();
      break;

    case C_END:   /* E */
      cif_end();
      break;

    case C_WIRE:   /* W */
      cif_wire();
      break;

    default:
      get_semi();
      break;
    }
  }
}


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

void read_cif(void)
{
  /* continue point in loop. */
  Char ans_str[fidleng + 1];
  node *t_main;
  Char errmsg[81];

  m_graphics_off();
  alpha_screen(CLR);
  m_alpha_on();
  getfilename(ans_str, "Name of input file? ", "");

  while (*ans_str != '\0' && strpos2(ans_str, "-ABORT", 1) == 0) {
    m_alpha_on();
    if (!dofixname(ans_str, errmsg, ".cif"))   /*dummy*/
      goto _L1;
    /* bad name! */

    TRY(try16);
      if (cif_fil != NULL)
	cif_fil = freopen(ans_str, "r", cif_fil);
      else
	cif_fil = fopen(ans_str, "r");
      if (cif_fil == NULL) {
	P_escapecode = -10;
	P_ioresult = FileNotFound;
	goto _Ltry16;
      }
      a_w_list = NULL;
      a_w_layer = 0;
      cell_scale = 2;
      t_main = main_;
      main_ = NULL;
      building_ports = NULL;
      defining_cell = false;
      d_set_bb = false;
      cif_prefix_found = false;
      printf("Reading from file:  %s\n", ans_str);
      TRY(try17);
	read_c_file();
      RECOVER(try17);
	show_error("Error in READ_CIF", false);
      ENDTRY(try17);
      if (cif_fil != NULL)
	fclose(cif_fil);
      cif_fil = NULL;   /* MAS  --  close the input file */
      main_ = t_main;
      set_bb(geom_cells);
      recl_a_w_node(&a_w_list);

    RECOVER2(try16,_Ltry16);
      show_error(ans_str, false);
    ENDTRY(try16);
_L1:
    putchar('\n');
    getfilename(ans_str, "Name of input file (<CR> if done)", "");
  }

  m_alpha_off();
}


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

void read_cif_file(Char *ans_str_)
{
  Char ans_str[fidleng + 1];
  node *t_main;
  Char errmsg[81];
  Char STR1[136];

  strcpy(ans_str, ans_str_);
  if (!dofixname(ans_str, errmsg, ".cif")) {   /*dummy*/
    sprintf(STR1, "Bad file name: %s", ans_str);
    show_error(STR1, false);
    return;
  }
  /* bad name! */
  TRY(try18);
    if (cif_fil != NULL)
      cif_fil = freopen(ans_str, "r", cif_fil);
    else
      cif_fil = fopen(ans_str, "r");
    if (cif_fil == NULL) {
      P_escapecode = -10;
      P_ioresult = FileNotFound;
      goto _Ltry18;
    }
    a_w_list = NULL;
    a_w_layer = 0;
    cell_scale = 2;
    t_main = main_;
    main_ = NULL;
    building_ports = NULL;
    defining_cell = false;
    d_set_bb = false;
    cif_prefix_found = false;
    printf("Reading from file:  %s\n", ans_str);
    TRY(try19);
      read_c_file();
    RECOVER(try19);
      show_error("Error in READ_CIF_FILE", false);
    ENDTRY(try19);
    if (cif_fil != NULL)
      fclose(cif_fil);
    cif_fil = NULL;   /* MAS  --  close the input file */
    main_ = t_main;
    set_bb(geom_cells);
    recl_a_w_node(&a_w_list);
    printf("Successfully read file: %s\n", ans_str);
    printf("Lambda is currently %0.2f microns.\n", lambda_to_microns / 100.0);
  RECOVER2(try18,_Ltry18);
    show_error(ans_str, false);
  ENDTRY(try18);
}


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

void list_cif_files(void)
{
  Char name[81];
  Char STR1[fidleng + 1];
  Char *TEMP;

  printf("\n\n");
  do {
    m_graphics_off();
    alpha_screen(CLR);
    m_alpha_on();
    printf("Directory? [ENTER to terminate] ");
    fgets(name, 81, stdin);
    TEMP = strchr(name, '\n');
    if (TEMP != NULL)
      *TEMP = 0;
    if (*name != '\0')
      strcpy(name, getfname(STR1, name));
  } while (*name != '\0' && strpos2(name, "-ABORT", 1) == 0);
  m_alpha_off();
  m_graphics_on();
}


/* module WOL_CIF */



/* End. */
