// *****************************************************************************
// *****************************************************************************
// Copyright 2014 - 2015, Cadence Design Systems
// 
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8. 
// 
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
// 
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
// 
//  $Author$
//  $Revision$
//  $Date$
//  $State:  $
// *****************************************************************************
// *****************************************************************************
 
// This program is the diffDef core program.  It has all the callback
// routines and write it out to a temporary file.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#   include <unistd.h>
#endif /* not WIN32 */
#include "defrReader.hpp"


char defaultName[64];
char defaultOut[64];
static int ignorePE = 0;
static int ignoreRN = 0;
static int ignoreVN = 0;
static int netSeCmp = 0;

// Global variables
FILE* fout;
void  *userData;
int numObjs;
int isSumSet;      // to keep track if within SUM
int isProp = 0;    // for PROPDEF
int begOperand;    // to keep track for constraint, to print - as the 1st char
static double curVer = 5.7;

// TX_DIR:TRANSLATION ON

void dataError() {
  fprintf(fout, "ERROR: returned user data is not correct!\n");
}


void checkType(defrCallbackType_e c) {
  if (c >= 0 && c <= defrDesignEndCbkType) {
    // OK
  } else {
    fprintf(fout, "ERROR: callback type is out of bounds!\n");
  }
}

// 05/24/2001 - Wanda da Rosa.  PCR 373170
// This function is added due to the rounding between machines are
// different.  For a 5, solaries will round down while hppa will roundup.
// This function will make sure it round up for all the machine
double checkDouble(double num) {
  long tempNum;
  if ((num > 1000004) || (num < -1000004)) {
     tempNum = (long)num;
     if ((tempNum%5) == 0)
        return num + 3;
  }
  return num;
}

int compMSL(defrCallbackType_e c, defiComponentMaskShiftLayer* co, defiUserData ud) {
  int i;

  checkType(c);
  if (ud != userData) dataError();

    if (co->numMaskShiftLayers()) {
	fprintf(fout, "\nCOMPONENTMASKSHIFT ");
	
	for (i = 0; i < co->numMaskShiftLayers(); i++) {
           fprintf(fout, "%s ", co->maskShiftLayer(i));
	}
	fprintf(fout, ";\n");
    }

  return 0;
}


// Component
int compf(defrCallbackType_e c, defiComponent* co, defiUserData ud) {
  int i;

  checkType(c);
  if (ud != userData) dataError();
//  missing GENERATE, FOREIGN
    fprintf(fout, "COMP %s %s", co->id(), co->name());
    if (co->hasNets()) {
        for (i = 0; i < co->numNets(); i++)
             fprintf(fout, " %s", co->net(i));
        fprintf(fout,"\n");
    } else
        fprintf(fout,"\n");
    if (co->isFixed()) 
        fprintf(fout, "COMP %s FIXED ( %d %d ) %s\n", co->id(),
                co->placementX(), co->placementY(), co->placementOrientStr());
    if (co->isCover()) 
        fprintf(fout, "COMP %s COVER ( %d %d ) %s\n", co->id(),
                co->placementX(), co->placementY(), co->placementOrientStr());
    if (co->isPlaced()) 
        fprintf(fout,"COMP %s PLACED ( %d %d ) %s\n", co->id(),
                co->placementX(), co->placementY(), co->placementOrientStr());
    if (co->isUnplaced()) 
        fprintf(fout,"COMP %s UNPLACED\n", co->id());
    if (co->hasSource())
        fprintf(fout, "COMP %s SOURCE %s\n", co->id(), co->source());
    if (co->hasGenerate())
        fprintf(fout, "COMP %s GENERATE %s %s\n", co->id(),
                co->generateName(), co->macroName());
    if (co->hasHalo()) {
        int left, bottom, right, top;
        (void) co->haloEdges(&left, &bottom, &right, &top);
        fprintf(fout, "COMP %s HALO", co->id());
        if (co->hasHaloSoft())
           fprintf(fout, " SOFT");
        fprintf(fout, " %d %d %d %d\n", left, bottom, right, top);
        
    }
    if (co->hasRouteHalo()) {
        fprintf(fout, "COMP %s ROUTEHALO %d %s %s\n", co->id(),
                co->haloDist(), co->minLayer(), co->maxLayer());
    }
    if (co->hasForeignName())
        fprintf(fout, "COMP %s FOREIGN %s %d %d %s\n", co->id(),
                co->foreignName(), co->foreignX(), co->foreignY(),
                co->foreignOri());
    if (co->hasWeight())
        fprintf(fout, "COMP %s WEIGHT %d\n", co->id(), co->weight());
    if (co->hasEEQ())
        fprintf(fout, "COMP %s EEQMASTER %s\n", co->id(), co->EEQ());
    if (co->hasRegionName())
        fprintf(fout, "COMP %s REGION %s\n", co->id(), co->regionName());
    if (co->hasRegionBounds()) {
        int *xl, *yl, *xh, *yh;
        int size;
        co->regionBounds(&size, &xl, &yl, &xh, &yh);
        for (i = 0; i < size; i++) { 
            fprintf(fout, "COMP %s REGION ( %d %d ) ( %d %d )\n", co->id(),
                    xl[i], yl[i], xh[i], yh[i]);
        }
    }
    if (co->maskShiftSize()) {
	fprintf(fout, "MASKSHIFT ");

        for (int i = co->maskShiftSize()-1; i >= 0; i--) {
            fprintf(fout, "%d", co->maskShift(i));
        }
        fprintf(fout, "\n");
    }
    if (co->numProps()) {
        for (i = 0; i < co->numProps(); i++) {
            fprintf(fout, "COMP %s PROP %s %s ", co->id(),
                    co->propName(i),
                    co->propValue(i));
            switch (co->propType(i)) {
               case 'R': fprintf(fout, "REAL ");
                         break;
               case 'I': fprintf(fout, "INT ");
                         break;
               case 'S': fprintf(fout, "STR ");
                         break;
               case 'Q': fprintf(fout, "QSTR ");
                         break;
               case 'N': fprintf(fout, "NUM ");
                         break;
            }
            fprintf(fout, "\n");
        }
    }

    --numObjs;
  return 0;
}

// Net
int netf(defrCallbackType_e c, defiNet* net, defiUserData ud) {
  // For net and special net.
  int         i, j, k, w, x, y, z, px, py, pz;
  defiPath*   p;
  defiSubnet* s;
  int         path;
  defiVpin   *vpin;
  defiShield* noShield;
  defiWire*   wire;
  int         nline;
  const char* layerName = "N/A";

  checkType(c);
  if (ud != userData) dataError();
  if (c != defrNetCbkType)
      fprintf(fout, "BOGUS NET TYPE  ");
  if (net->pinIsMustJoin(0))
      fprintf(fout, "NET MUSTJOIN ");
  else
      fprintf(fout, "NET %s ", net->name());
 
  // compName & pinName
  for (i = 0; i < net->numConnections(); i++) {
      fprintf(fout, "\nNET %s ( %s %s ) ", net->name(), net->instance(i),
              net->pin(i));
  }

  if (net->hasNonDefaultRule())
      fprintf(fout, "\nNET %s NONDEFAULTRULE %s", net->name(),
              net->nonDefaultRule());
 
  for (i = 0; i < net->numVpins(); i++) {
      vpin = net->vpin(i);
      fprintf(fout, "\nNET %s %s", net->name(), vpin->name());
      if (vpin->layer())
          fprintf(fout, " %s", vpin->layer());
      fprintf(fout, " %d %d %d %d", vpin->xl(), vpin->yl(), vpin->xh(),
              vpin->yh());
      if (vpin->status() != ' ') {
          switch (vpin->status()) {
              case 'P':
              case 'p':
                   fprintf(fout, " PLACED"); 
                   break;
              case 'F':
              case 'f':
                   fprintf(fout, " FIXED"); 
                   break;
              case 'C':
              case 'c':
                   fprintf(fout, " COVER"); 
                   break;
          }
          fprintf(fout, " %d %d", vpin->xLoc(), vpin->yLoc());
          if (vpin->orient() != -1)
              fprintf(fout, " %s", vpin->orientStr());
      }
  }

  // regularWiring
  if (net->numWires()) {
    for (i = 0; i < net->numWires(); i++) {
      wire = net->wire(i);
      for (j = 0; j < wire->numPaths(); j++) {
        p = wire->path(j);
        p->initTraverse();
        fprintf(fout, "\nNET %s %s", net->name(), wire->wireType());
        nline = 0;
        while ((path = (int)p->next()) != DEFIPATH_DONE) {
          switch (path) {
            case DEFIPATH_LAYER:
                 if (!netSeCmp)
                    fprintf(fout, " %s", p->getLayer());
                 layerName = p->getLayer();
                 px = py = pz = -99;     // reset the 1 set of point to 0
                 break;
	    case DEFIPATH_MASK:
		 fprintf(fout, "MASK %d ", p->getMask());
                 break;
	    case DEFIPATH_VIAMASK:
                     fprintf(fout, "MASK %d%d%d ", 
                             p->getViaTopMask(), 
                             p->getViaCutMask(),
                             p->getViaBottomMask());
                 break;
            case DEFIPATH_VIA:
                 if (!netSeCmp) {
                    if (!ignoreVN)
                       fprintf(fout, " %s", p->getVia());
                 } else {
                    if (nline) {
                       if (!ignoreVN)
                          fprintf(fout, "\nNET %s %s ( %d %d ) %s", net->name(),
                               wire->wireType(), px, py, p->getVia());
                       else
                          fprintf(fout, "\nNET %s %s ( %d %d )", net->name(),
                               wire->wireType(), px, py);
                    } else {
                       if (!ignoreVN)
                          fprintf(fout, " ( %d %d ) %s", px, py, p->getVia());
                       else
                          fprintf(fout, " ( %d %d )", px, py);
                    }
                    px = py = pz = -99;     // reset the 1 set of point to 0
                 }
                 nline = 1;
                 break;
	    case DEFIPATH_RECT:
		 p->getViaRect(&w, &x, &y, &z);
                 fprintf(fout, "RECT ( %d %d %d %d ) ", w, x, y, z);
                 break;
	    case DEFIPATH_VIRTUALPOINT:
	         p->getVirtualPoint(&x, &y);
		 fprintf(fout, "VIRTUAL ( %d %d ) ", x, y);
                 break;
            case DEFIPATH_VIAROTATION:
                 fprintf(fout, "%d ",p->getViaRotation());
                 nline = 1;
                 break;
            case DEFIPATH_WIDTH:
                 fprintf(fout, " %d ", p->getWidth());
                 break;
            case DEFIPATH_POINT:
                 p->getPoint(&x, &y);
                 if (!netSeCmp) {
                    if (!nline) {
                       fprintf(fout, " ( %d %d )", x, y);
                       nline = 1; 
                    } else {
                       fprintf(fout, "\nNET %s %s %s ( %d %d )", net->name(),
                               wire->wireType(), layerName, x, y);
                    }
                 } else {
                    if ((px == -99) && (py == -99)) {
                       px = x;
                       py = y;
                    } else {
                       if (nline)
                          fprintf(fout, "\nNET %s %s %s", net->name(),
                                  wire->wireType(), layerName);
                       if (px < x) {
                          fprintf (fout, " ( %d %d ) ( %d %d )", px, py, x, y);
                       } else if (px == x) {
                          if (py < y) 
                              fprintf (fout, " ( %d %d ) ( %d %d )",
                                       px, py, x, y);
                          else
                              fprintf (fout, " ( %d %d ) ( %d %d )",
                                       x, y, px, py);
                       } else {  // px > x
                          fprintf (fout, " ( %d %d ) ( %d %d )", x, y, px, py);
                       }
                       px = x;
                       py = y;
                       nline = 1; 
                    }
                 }
                 break;
            case DEFIPATH_FLUSHPOINT:
                 p->getFlushPoint(&x, &y, &z);
                 if (!netSeCmp) {
                    if (!nline) {
                       fprintf(fout, " ( %d %d %d )", x, y, z);
                    } else {
                       fprintf(fout, "\nNET %s %s %s ( %d %d %d )", net->name(),
                               wire->wireType(), layerName, x, y, z);
                    }
                 } else {
                    if ((px == -99) && (py == -99) && (pz == -99)) {
                       px = x;
                       py = y;
                       pz = z;
                    } else {
                       if (nline)
                          fprintf(fout, "\nNET %s %s %s", net->name(),
                                  wire->wireType(), layerName);
                       if (px < x) {
                          if (pz != -99)
                             fprintf (fout, " ( %d %d %d ) ( %d %d %d )",
                                      px, py, pz, x, y, z);
                          else
                             fprintf (fout, " ( %d %d ) ( %d %d %d )",
                                      px, py, x, y, z);
                       } else if (px == x) {
                          if (py < y)  {
                             if (pz != -99)
                                fprintf (fout, " ( %d %d %d ) ( %d %d %d )",
                                         px, py, pz, x, y, z);
                             else
                                fprintf (fout, " ( %d %d ) ( %d %d %d )",
                                         px, py, x, y, z);
                          } else {
                             if (pz != -99)
                                fprintf (fout, " ( %d %d %d ) ( %d %d %d )",
                                         x, y, z, px, py, pz);
                             else
                                fprintf (fout, " ( %d %d %d ) ( %d %d )",
                                         x, y, z, px, py);
                          }
                       } else {  // px > x
                          if (pz != -99)
                             fprintf (fout, " ( %d %d %d ) ( %d %d %d )",
                                      x, y, z, px, py, pz);
                          else
                             fprintf (fout, " ( %d %d %d ) ( %d %d )",
                                      x, y, z, px, py);
                       }
                       px = x;
                       py = y;
                       pz = z;
                       nline = 1; 
                    }
                 }
                 break;
            case DEFIPATH_TAPER:
                 fprintf(fout, " TAPER");
                 break;
            case DEFIPATH_TAPERRULE:
                 fprintf(fout, " TAPERRULE %s",p->getTaperRule());
                 break;
          }
        }
      }
    }
  }

  // shieldnet
  if (net->numShieldNets()) {
     for (i = 0; i < net->numShieldNets(); i++)
         fprintf(fout, "\nNET %s SHIELDNET %s ", net->name(),
                 net->shieldNet(i));
  }
  if (net->numNoShields()) {
     for (i = 0; i < net->numNoShields(); i++) {
         noShield = net->noShield(i);
         for (j = 0; j < noShield->numPaths(); j++) {
            p = noShield->path(j);
            p->initTraverse();
            fprintf(fout, "\nNET %s NOSHIELD", net->name());
            nline = 0;
            while ((path = (int)p->next()) != DEFIPATH_DONE) {
               switch (path) {
                 case DEFIPATH_LAYER:
                      fprintf(fout, " %s", p->getLayer());
                      layerName = p->getLayer();
                      break;
				 case DEFIPATH_MASK:
					  fprintf(fout, "MASK %d ", p->getMask());
					  break;
                 case DEFIPATH_VIAMASK:
                      fprintf(fout, "MASK %d%d%d ", 
                              p->getViaTopMask(), 
                              p->getViaCutMask(),
                              p->getViaBottomMask());
                      break;
                 case DEFIPATH_VIA:
                      if (!ignoreVN)
                         fprintf(fout, " %s", p->getVia());
                      nline = 1;
                      break;
                 case DEFIPATH_VIAROTATION:
                      fprintf(fout, " %d", p->getViaRotation());
                      nline = 1;
                      break;
                 case DEFIPATH_WIDTH:
                      fprintf(fout, " %d", p->getWidth());
                      break;
                 case DEFIPATH_POINT:
                      p->getPoint(&x, &y);
                      if (!nline) {
                         fprintf(fout, " ( %d %d )", x, y);
                         nline = 1;
                      } else {
                         fprintf(fout, "\nNET %s %s ( %d %d )",
                                 net->name(), layerName, x, y);
                         nline = 1;
                      }
                      break;
                 case DEFIPATH_FLUSHPOINT:
                      p->getFlushPoint(&x, &y, &z);
                      if (!nline) {
                         fprintf(fout, " ( %d %d )", x, y);
                         nline = 1;
                      } else {
                         fprintf(fout, "\nNET %s %s ( %d %d )",
                                 net->name(), layerName, x, y);
                         nline = 1;
                      }
                 case DEFIPATH_TAPER:
                      fprintf(fout, " TAPER");
                      break;
                 case DEFIPATH_TAPERRULE:
                      fprintf(fout, " TAPERRULE %s",
                              p->getTaperRule());
                      break;
               }
            }
         }
     }
  }

  if (net->hasSubnets()) {
    for (i = 0; i < net->numSubnets(); i++) {
      s = net->subnet(i);
 
      if (s->numConnections()) {
          for (j = 0; j < s->numConnections(); j++) {
              if (s->pinIsMustJoin(0))
                  fprintf(fout, "\nNET MUSTJOIN");
              else
                  fprintf(fout, "\nNET %s", s->name());
              fprintf(fout, " ( %s %s )", s->instance(j), s->pin(j));
          }
      }
 
      for (j = 0; j < s->numWires(); j++) {
        wire = s->wire(j);
        if (s->numPaths()) {
           for (k = 0; k < wire->numPaths(); k++) {
             int elem;
             p = wire->path(k);
             p->initTraverse();
             fprintf(fout, "\nNET %s %s", s->name(), wire->wireType()); 
             nline = 0;
             elem = p->next();
             while (elem) { 
                switch (elem) {
                  case DEFIPATH_LAYER:
                       fprintf(fout, " LAYER %s",  p->getLayer());
                       layerName = p->getLayer();
                       break;
		  case DEFIPATH_MASK:
		       fprintf(fout, "MASK %d ", p->getMask());
		       break;
                  case DEFIPATH_VIAMASK:
                       fprintf(fout, "MASK %d%d%d ", 
                               p->getViaTopMask(), 
                               p->getViaCutMask(),
                               p->getViaBottomMask());
                       break;
                  case DEFIPATH_VIA:
                       if (!ignoreVN)
                          fprintf(fout, " VIA %s", p->getVia());
                       nline = 1;
                       break;
                  case DEFIPATH_VIAROTATION:
                       fprintf(fout, " VIAROTATION %d", p->getViaRotation());
                       nline = 1;
                       break;
                  case DEFIPATH_WIDTH:
                       fprintf(fout, " WIDTH %d", p->getWidth());
                       break;
                  case DEFIPATH_POINT:
                       p->getPoint(&x, &y);
                       if (!nline) {
                          fprintf(fout, " POINT %d %d", x, y);
                          nline = 1;
                       } else {
                          fprintf(fout, "\nNET %s %s %s POINT %d %d",
                                  s->name(), wire->wireType(), layerName, x, y);
                          nline = 1;
                       }
                       break;
                  //case DEFIPATH_FLUSHPOINT:
                       //l = 0;
                       //p->getFlushPoint(i1, i2, ext);
                       //while (i1[l] && i2[l] && ext[l]) {
                          //fprintf(fout, "NET %s FLUSHPOINT %d %d %d\n",
                                  //s->name(), i1[l], i2[l], ext[l]);
                          //l++;
                       //}
                       //break;
                  case DEFIPATH_TAPERRULE:
                       fprintf(fout, " TAPERRULE %s", p->getTaperRule());
                       break;
                  case DEFIPATH_SHAPE:
                       fprintf(fout, " SHAPE %s", p->getShape());
                       break;
                  case DEFIPATH_STYLE:
                       fprintf(fout, " STYLE %d", p->getStyle());
                       break;
               }
               elem = p->next();
            }
          }
        }
      }
    }
  }

  /* Put the following all in one line */
  if (net->hasWeight() || net->hasCap() || net->hasSource() ||
      net->hasPattern() || net->hasOriginal() || net->hasUse()) {
      fprintf(fout, "\nNET %s ", net->name());

     if (net->hasWeight())
       fprintf(fout, "WEIGHT %d ", net->weight());
     if (net->hasCap())
       fprintf(fout, "ESTCAP %g ", checkDouble(net->cap()));
     if (net->hasSource())
       fprintf(fout, "SOURCE %s ", net->source());
     if (net->hasFixedbump())
       fprintf(fout, "FIXEDBUMP ");
     if (net->hasFrequency())
       fprintf(fout, "FREQUENCY %g ", net->frequency());
     if (net->hasPattern())
       fprintf(fout, "PATTERN %s ", net->pattern());
     if (net->hasOriginal())
       fprintf(fout, "ORIGINAL %s ", net->original());
     if (net->hasUse())
       fprintf(fout, "USE %s ", net->use());
  }

  fprintf (fout, "\n");
  --numObjs;
  return 0;
}


// Special Net
int snetf(defrCallbackType_e c, defiNet* net, defiUserData ud) {
  // For net and special net.
  int        i, j, x, y, z;
  char       *layerName;
  double     dist, left, right;
  defiPath   *p;
  defiSubnet *s;
  int        path;
  defiShield* shield;
  defiWire   *wire;
  int        nline;
  const char* sNLayerName = "N/A";
  int        numX, numY, stepX, stepY;

  checkType(c);
  if (ud != userData) dataError();
  if (c != defrSNetCbkType)
      fprintf(fout, "BOGUS NET TYPE  ");

  // compName & pinName
  if (net->numConnections() > 0) {
     for (i = 0; i < net->numConnections(); i++)
         fprintf (fout, "SNET %s ( %s %s )\n", net->name(), net->instance(i),
                  net->pin(i));
  }

  if (net->numRectangles()) {  // 5.6

     for (i = 0; i < net->numRectangles(); i++) {
       if (curVer >= 5.8 ) {
         fprintf (fout, "\nSNET %s ", net->name());
	 if (strcmp(net->rectRouteStatus(i), "") != 0) {
	   fprintf(fout, "%s ", net->rectRouteStatus(i));
	   if (strcmp(net->rectRouteStatus(i), "SHIELD") == 0) {
	      fprintf(fout, "%s ", net->rectRouteStatusShieldName(i));
	   }
         }
         if (strcmp(net->rectShapeType(i), "") != 0) {
	   fprintf(fout, "SHAPE %s ", net->rectShapeType(i));
         }
       }
       if (net->rectMask(i)) {
	  fprintf(fout, "MASK %d RECT %s %d %d %d %d", 
		  net->rectMask(i), net->rectName(i),
		  net->xl(i), net->yl(i), net->xh(i),
                  net->yh(i));
       } else {
	  fprintf(fout, "RECT %s %d %d %d %d", net->name(),
               net->xl(i), net->yl(i), net->xh(i),
               net->yh(i));
       }
     }
  }

  if (net->numPolygons()) {  
    struct defiPoints points;

    for (i = 0; i < net->numPolygons(); i++) {
      fprintf (fout, "\nSNET %s ", net->name());
      if (curVer >= 5.8 ) {
	 if (strcmp(net->polyRouteStatus(i), "") != 0) {
	   fprintf(fout, "%s ", net->polyRouteStatus(i));
	   if (strcmp(net->polyRouteStatus(i), "SHIELD") == 0) {
	      fprintf(fout, "%s ", net->polyRouteStatusShieldName(i));
	   }
         }
         if (strcmp(net->polyShapeType(i), "") != 0) {
	   fprintf(fout, "SHAPE %s ", net->polyShapeType(i));
         }
      }
      if (net->polyMask(i)) {
	  fprintf(fout, "MASK %d POLYGON % s ", 
		  net->polyMask(i),
		  net->polygonName(i));
      } else {
	  fprintf(fout, "POLYGON %s", net->polygonName(i));
      }

      points = net->getPolygon(i);
      for (j = 0; j < points.numPoints; j++)
        fprintf(fout, " %d %d", points.x[j], points.y[j]);
    }
  }

   if (curVer >= 5.8 && net->numViaSpecs()) {
     for (i = 0; i < net->numViaSpecs(); i++) {
       fprintf (fout, "\nSNET %s ", net->name());
       if (strcmp(net->viaRouteStatus(i), "") != 0) {
	fprintf(fout, "%s ", net->viaRouteStatus(i));
	if (strcmp(net->viaRouteStatus(i), "SHIELD") == 0) {
	      fprintf(fout, "%s ", net->viaRouteStatusShieldName(i));
	   }
       }
       if (strcmp(net->viaShapeType(i), "") != 0) {
	fprintf(fout, "SHAPE %s ", net->viaShapeType(i));
       }
       if (net->topMaskNum(i) || net->cutMaskNum(i) || net->bottomMaskNum(i)) {
	fprintf(fout, "MASK %d%d%d VIA %s ", net->topMaskNum(i), 
                net->cutMaskNum(i),
                net->bottomMaskNum(i),
		net->viaName(i));
       } else {
	fprintf(fout, "\n  VIA %s ", net->viaName(i));
       }
       fprintf(fout, " %s", net->viaOrientStr(i));
      
       defiPoints points = net->getViaPts(i);

       for (int j = 0; j < points.numPoints; j++) {
          fprintf(fout, " %d %d", points.x[j], points.y[j]);
       }
       fprintf(fout, ";\n"); 
     }
  } 


  // specialWiring
  if (net->numWires()) {
     for (i = 0; i < net->numWires(); i++) {
        wire = net->wire(i);
        for (j = 0; j < wire->numPaths(); j++) {
           p = wire->path(j);
           fprintf(fout, "\nSNET %s %s", net->name(), wire->wireType());
           nline = 0;
           p->initTraverse();
           while ((path = (int)p->next()) != DEFIPATH_DONE) {
              switch (path) {
                case DEFIPATH_LAYER:
                     fprintf(fout, " %s", p->getLayer());
                     sNLayerName = p->getLayer();
                     break;
		case DEFIPATH_MASK:
		     fprintf(fout, "MASK %d ", p->getMask());
		     break;
                case DEFIPATH_VIAMASK:
                     fprintf(fout, "MASK %d%d%d ", 
                             p->getViaTopMask(), 
                             p->getViaCutMask(),
                             p->getViaBottomMask());
                    break;
                case DEFIPATH_VIA:
                     if (!ignoreVN)
                        fprintf(fout, " %s", p->getVia());
                     nline = 1;
                     break;
                case DEFIPATH_VIAROTATION:
                     fprintf(fout, " %d", p->getViaRotation());
                     nline = 1;
                     break;
                case DEFIPATH_VIADATA:
                     p->getViaData(&numX, &numY, &stepX, &stepY);
                     fprintf(fout, " DO %d BY %d STEP %d %d", numX, numY,
                             stepX, stepY);
                     nline = 1;
                     break;
                case DEFIPATH_WIDTH:
                     fprintf(fout, " %d", p->getWidth());
                     break;
                case DEFIPATH_POINT:
                     p->getPoint(&x, &y);
                     if (!nline) {
                        fprintf(fout, " ( %d %d ) ", x, y);
                        nline = 1;
                     } else {
                        fprintf(fout, "\nSNET %s %s %s ( %d %d )", net->name(),
                                wire->wireType(), sNLayerName, x, y);
                        nline = 1;
                     }
                     break;
                case DEFIPATH_FLUSHPOINT:
                     p->getFlushPoint(&x, &y, &z);
                     fprintf(fout, "( %d %d %d ) ", x, y, z);
                     nline = 1;
                     break;
                case DEFIPATH_TAPER:
                     fprintf(fout, " TAPER");
                     break;
                case DEFIPATH_SHAPE:
                     fprintf(fout, " + SHAPE %s", p->getShape());
                     break;
                case DEFIPATH_STYLE:
                     fprintf(fout, " + STYLE %d", p->getStyle());
                     break;
              }
           }
        }
     }
  }

  if (net->hasSubnets()) {
     for (i = 0; i < net->numSubnets(); i++) {
       s = net->subnet(i);
       if (s->numConnections()) {
           if (s->pinIsMustJoin(0))
               fprintf(fout, "\nSNET %s MUSTJOIN", net->name());
           else
               fprintf(fout, "\nSNET %s", net->name());
           for (j = 0; j < s->numConnections(); j++) {
               fprintf(fout, "( %s %s ) ", s->instance(j), s->pin(j));
           }
      }
 
      // regularWiring
      if (s->numWires()) {
         for (i = 0; i < s->numWires(); i++) {
            wire = s->wire(i);
            for (j = 0; j < wire->numPaths(); j++) {
              p = wire->path(j);
              p->initTraverse();
              fprintf(fout, "\nSNET %s %s", net->name(), wire->wireType());
              nline = 0;
              while ((path = (int)p->next()) != DEFIPATH_DONE) {
                switch (path) {
                  case DEFIPATH_LAYER:
                       fprintf(fout, " %s", p->getLayer());
                       sNLayerName = p->getLayer();
                       break;
                  case DEFIPATH_VIA:
                       if (!ignoreVN)
                          fprintf(fout, " %s", p->getVia());
                       break;
		  case DEFIPATH_MASK:
		       fprintf(fout, "MASK %d ", p->getMask());
		       break;
                  case DEFIPATH_VIAMASK:
                       fprintf(fout, "MASK %d%d%d ", 
                           p->getViaTopMask(), 
                           p->getViaCutMask(),
                           p->getViaBottomMask());
                   break;

                  case DEFIPATH_VIAROTATION:
                       fprintf(fout, " %d", p->getViaRotation());
                       break;
                  case DEFIPATH_WIDTH:
                       fprintf(fout, " %d", p->getWidth());
                       break;
                  case DEFIPATH_POINT:
                       p->getPoint(&x, &y);
                       if (!nline) {
                          fprintf(fout, "( %d %d ) ", x, y);
                          nline = 1;
                       } else {
                          fprintf(fout, "\nSNET %s %s %s ( %d %d ) ",
                                  net->name(), wire->wireType(), sNLayerName,
                                  x, y);
                          nline = 1;
                       }
                       break;
                  case DEFIPATH_TAPER:
                       fprintf(fout, " TAPER");
                       break;
                }
              }
            }
         }
      }
    }
  }
 
  if (net->numProps()) {
    for (i = 0; i < net->numProps(); i++) {
        fprintf(fout, "\nSNET %s PROP %s %s ", net->name(),
                net->propName(i), net->propValue(i));
        switch (net->propType(i)) {
           case 'R': fprintf(fout, "REAL ");
                     break;
           case 'I': fprintf(fout, "INT ");
                     break;
           case 'S': fprintf(fout, "STR ");
                     break;
           case 'Q': fprintf(fout, "QSTR ");
                     break;
           case 'N': fprintf(fout, "NUM ");
                     break;
        }
    }
  }

  // SHIELD
  // testing the SHIELD for 5.3
  if (net->numShields()) {
    for (i = 0; i < net->numShields(); i++) {
       shield = net->shield(i);
       for (j = 0; j < shield->numPaths(); j++) {
          p = shield->path(j);
          fprintf(fout, "\nSNET %s SHIELD %s", net->name(),
                  shield->shieldName());
          p->initTraverse();
          while ((path = (int)p->next()) != DEFIPATH_DONE) {
             switch (path) {
               case DEFIPATH_LAYER:
                    fprintf(fout, " %s", p->getLayer());
                    sNLayerName = p->getLayer();
                    break;
               case DEFIPATH_VIA:
                    if (!ignoreVN)
                       fprintf(fout, " %s", p->getVia());
                    break;
	       case DEFIPATH_MASK:
		    fprintf(fout, "MASK %d ", p->getMask());
		    break;
               case DEFIPATH_VIAMASK:
                   fprintf(fout, "MASK %d%d%d ", 
                           p->getViaTopMask(), 
                           p->getViaCutMask(),
                           p->getViaBottomMask());
                   break;
               case DEFIPATH_VIAROTATION:
                    fprintf(fout, " %d", p->getViaRotation());
                    break;
               case DEFIPATH_WIDTH:
                    fprintf(fout, " %d", p->getWidth());
                    break;
               case DEFIPATH_POINT:
                    p->getPoint(&x, &y);
                    if (!nline) {
                       fprintf(fout, "( %d %d ) ", x, y);
                       nline = 1;
                    } else {
                      fprintf(fout, "\nSNET %s SHIELD %s %s ( %d %d )",
                              net->name(), shield->shieldName(), sNLayerName,
                              x, y);
                    }
                    break;
               case DEFIPATH_TAPER:
                    fprintf(fout, " TAPER");
                    break;
             }
          }
       }
    }
  }

  // layerName width
  if (net->hasWidthRules()) {
    fprintf(fout, "\nSNET %s", net->name());
    for (i = 0; i < net->numWidthRules(); i++) {
        net->widthRule(i, &layerName, &dist);
        fprintf (fout, " WIDTH %s %g ", layerName, checkDouble(dist));
    }
  }

  // layerName spacing
  if (net->hasSpacingRules()) {
    fprintf(fout, "\nSNET %s", net->name());
    for (i = 0; i < net->numSpacingRules(); i++) {
        net->spacingRule(i, &layerName, &dist, &left, &right);
        if (left == right)
            fprintf (fout, " SPACING %s %g ", layerName, checkDouble(dist));
        else
            fprintf (fout, " SPACING %s %g RANGE %g %g ",
                     layerName, checkDouble(dist), checkDouble(left),
                     checkDouble(right));
    }
  }

  if (net->hasVoltage() || net->hasWeight() || net->hasCap() ||
      net->hasSource() || net->hasPattern() || net->hasOriginal() ||
      net->hasUse()) {
    fprintf(fout, "\nSNET %s", net->name());
    if (net->hasVoltage())
      fprintf(fout, " VOLTAGE %g", checkDouble(net->voltage()));
    if (net->hasWeight())
      fprintf(fout, " WEIGHT %d", net->weight());
    if (net->hasCap())
      fprintf(fout, " ESTCAP %g", checkDouble(net->cap()));
    if (net->hasSource())
      fprintf(fout, " SOURCE %s", net->source());
    if (net->hasPattern())
      fprintf(fout, " PATTERN %s", net->pattern());
    if (net->hasOriginal())
      fprintf(fout, " ORIGINAL %s", net->original());
    if (net->hasUse())
      fprintf(fout, " USE %s", net->use());
  }

  fprintf(fout,"\n");
  --numObjs;
  return 0;
}

int ndr(defrCallbackType_e c, defiNonDefault* nd, defiUserData ud) {
  // For nondefaultrule
  int i;

  checkType(c);
  if (ud != userData) dataError();
  if (c != defrNonDefaultCbkType)
      fprintf(fout, "BOGUS NONDEFAULTRULE TYPE  ");
  fprintf(fout, "NDR %s", nd->name());
  if (nd->hasHardspacing())
     fprintf(fout, " HARDSPACING\n");
  fprintf(fout, "\n");
  for (i = 0; i < nd->numLayers(); i++) {
    fprintf(fout, "NDR %s LAYER %s", nd->name(), nd->layerName(i));
    fprintf(fout, " WIDTH %d", nd->layerWidthVal(i));
    if (nd->hasLayerDiagWidth(i))
      fprintf(fout, " DIAGWIDTH %d",
              nd->layerDiagWidthVal(i));
    if (nd->hasLayerSpacing(i))
      fprintf(fout, " SPACING %d", nd->layerSpacingVal(i));
    if (nd->hasLayerWireExt(i))
      fprintf(fout, " WIREEXT %d", nd->layerWireExtVal(i));
    fprintf(fout, "\n");
  }
  for (i = 0; i < nd->numVias(); i++)
    fprintf(fout, "NDR %s VIA %s\n", nd->name(), nd->viaName(i));
  for (i = 0; i < nd->numViaRules(); i++)
    fprintf(fout, "NDR %s VIARULE %s\n", nd->name(), nd->viaRuleName(i));
  for (i = 0; i < nd->numMinCuts(); i++)
    fprintf(fout, "NDR %s MINCUTS %s %d\n", nd->name(), nd->cutLayerName(i),
            nd->numCuts(i));
  for (i = 0; i < nd->numProps(); i++)
    fprintf(fout, "NDR %s PROPERTY %s %s\n", nd->name(), nd->propName(i),
              nd->propValue(i));
  --numObjs;
  return 0;
}

// Technology
int tname(defrCallbackType_e c, const char* string, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "TECHNOLOGY %s\n", string);
  return 0;
}

// Design
int dname(defrCallbackType_e c, const char* string, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "DESIGN %s\n", string);

  return 0;
}


char* address(const char* in) {
  return ((char*)in);
}

// Assertion or Constraints
void operand(defrCallbackType_e c, defiAssertion* a, int ind) {
  int i, first = 1;
  char* netName;
  char* fromInst, * fromPin, * toInst, * toPin;

  if (a->isSum()) {
      // Sum in operand, recursively call operand
      fprintf(fout, "ASSERTIONS/CONSTRAINTS SUM ( ");
      a->unsetSum();
      isSumSet = 1;
      begOperand = 0;
      operand (c, a, ind);
      fprintf(fout, ") ");
  } else {
      // operand
      if (ind >= a->numItems()) {
          fprintf(fout, "ERROR: when writing out SUM in Constraints.\n");
          return;
       }
      if (begOperand) {
         fprintf(fout, "ASSRT/CONSTR ");
         begOperand = 0;
      }
      for (i = ind; i < a->numItems(); i++) {
          if (a->isNet(i)) {
              a->net(i, &netName);
              if (!first)
                  fprintf(fout, ", "); // print , as separator
              fprintf(fout, "NET %s ", netName); 
          } else if (a->isPath(i)) {
              a->path(i, &fromInst, &fromPin, &toInst,
                                     &toPin);
              if (!first)
                  fprintf(fout, ", ");
              fprintf(fout, "PATH %s %s %s %s ", fromInst, fromPin, toInst,
                      toPin);
          } else if (isSumSet) {
              // SUM within SUM, reset the flag
              a->setSum();
              operand(c, a, i);
          }
          first = 0;
      } 
      
  }
}

// Assertion or Constraints
int constraint(defrCallbackType_e c, defiAssertion* a, defiUserData ud) {
  // Handles both constraints and assertions

  checkType(c);
  if (ud != userData) dataError();
  if (a->isWiredlogic())
      // Wirelogic
      fprintf(fout, "ASSRT/CONSTR WIREDLOGIC %s + MAXDIST %g\n",
              a->netName(), checkDouble(a->fallMax()));
  else {
      // Call the operand function
      isSumSet = 0;    // reset the global variable
      begOperand = 1;
      operand (c, a, 0);
      // Get the Rise and Fall
      if (a->hasRiseMax())
          fprintf(fout, " RISEMAX %g ", checkDouble(a->riseMax()));
      if (a->hasFallMax())
          fprintf(fout, " FALLMAX %g ", checkDouble(a->fallMax()));
      if (a->hasRiseMin())
          fprintf(fout, " RISEMIN %g ", checkDouble(a->riseMin()));
      if (a->hasFallMin())
          fprintf(fout, " FALLMIN %g ", checkDouble(a->fallMin()));
      fprintf(fout, "\n");
  }
  --numObjs;
  return 0;
}


// Property definitions
int prop(defrCallbackType_e c, defiProp* p, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  if (strcmp(p->propType(), "design") == 0)
      fprintf(fout, "PROPDEF DESIGN %s ", p->propName());
  else if (strcmp(p->propType(), "net") == 0)
      fprintf(fout, "PROPDEF NET %s ", p->propName());
  else if (strcmp(p->propType(), "component") == 0)
      fprintf(fout, "PROPDEF COMP %s ", p->propName());
  else if (strcmp(p->propType(), "specialnet") == 0)
      fprintf(fout, "PROPDEF SNET %s ", p->propName());
  else if (strcmp(p->propType(), "group") == 0)
      fprintf(fout, "PROPDEF GROUP %s ", p->propName());
  else if (strcmp(p->propType(), "row") == 0)
      fprintf(fout, "PROPDEF ROW %s ", p->propName());
  else if (strcmp(p->propType(), "componentpin") == 0)
      fprintf(fout, "PROPDEF COMPPIN %s ", p->propName());
  else if (strcmp(p->propType(), "region") == 0)
      fprintf(fout, "PROPDEF REGION %s ", p->propName());
  else if (strcmp(p->propType(), "nondefaultrule") == 0)
      fprintf(fout, "PROPDEF NONDEFAULTRULE %s ", p->propName());
  if (p->dataType() == 'I')
      fprintf(fout, "INT ");
  if (p->dataType() == 'R')
      fprintf(fout, "REAL ");
  if (p->dataType() == 'S')
      fprintf(fout, "STR ");
  if (p->dataType() == 'Q')
      fprintf(fout, "STR ");
  if (p->hasRange()) {
      fprintf(fout, "RANGE %g %g ", checkDouble(p->left()),
                    checkDouble(p->right()));
  }
  if (p->hasNumber())
      fprintf(fout, "%g ", checkDouble(p->number()));
  if (p->hasString())
      fprintf(fout, "\"%s\" ", p->string());
  fprintf(fout, "\n");

  return 0;
}


// History
int hist(defrCallbackType_e c, const char* h, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "HIST %s\n", h);
  return 0;
}


// Busbitchars
int bbn(defrCallbackType_e c, const char* h, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "BUSBITCHARS \"%s\" \n", h);
  return 0;
}


// Version
int vers(defrCallbackType_e c, double d, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "VERSION %g\n", d);

  curVer = d;
  return 0;
}


// Units
int units(defrCallbackType_e c, double d, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "UNITS DISTANCE MICRONS %g\n", checkDouble(d));
  return 0;
}


// Casesensitive
int casesens(defrCallbackType_e c, int d, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  if (d == 1)
     fprintf(fout, "NAMESCASESENSITIVE OFF\n", d);
  else
     fprintf(fout, "NAMESCASESENSITIVE ON\n", d);
  return 0;
}


// Site, Canplace, Cannotoccupy, Diearea, Pin, Pincap, DefaultCap,
// Row, Gcellgrid, Track, Via, Scanchain, IOtiming, Flooplan,
// Region, Group, TiminDisable, Pin property
int cls(defrCallbackType_e c, void* cl, defiUserData ud) {
  defiSite* site;  // Site and Canplace and CannotOccupy
  defiBox* box;  // DieArea and 
  defiPinCap* pc;
  defiPin* pin;
  int i, j, k;
  defiRow* row;
  defiTrack* track;
  defiGcellGrid* gcg;
  defiVia* via;
  defiRegion* re;
  defiGroup* group;
  defiComponentMaskShiftLayer* maskShiftLayer = NULL;
  defiScanchain* sc;
  defiIOTiming* iot;
  defiFPC* fpc;
  defiTimingDisable* td;
  defiPartition* part;
  defiPinProp* pprop;
  defiBlockage* block;
  defiSlot* slot;
  defiFill* fill;
  defiStyles* styles;
  int xl, yl, xh, yh;
  char *name, *a1, *b1;
  char **inst, **inPin, **outPin;
  int  *bits;
  int  size;
  int corner, typ;
  const char *itemT;
  char dir;
  defiPinAntennaModel* aModel;
  char *tmpPinName = NULL;
  char *extraPinName = NULL;
  char *pName = NULL;
  char *tmpName = NULL;
  struct defiPoints points;

  checkType(c);
  if (ud != userData) dataError();
  switch (c) {

  case defrSiteCbkType :
         site = (defiSite*)cl;
         fprintf(fout, "SITE %s %g %g %s ", site->name(),
                 checkDouble(site->x_orig()), checkDouble(site->y_orig()),
                 site->orientStr());
         fprintf(fout, "DO %g BY %g STEP %g %g\n",
                 checkDouble(site->x_num()), checkDouble(site->y_num()),
                 checkDouble(site->x_step()), checkDouble(site->y_step()));
         break;
  case defrCanplaceCbkType :
         site = (defiSite*)cl;
         fprintf(fout, "CANPLACE %s %g %g %s ", site->name(),
                 checkDouble(site->x_orig()), checkDouble(site->y_orig()),
                 site->orientStr());
         fprintf(fout, "DO %g BY %g STEP %g %g\n",
                 checkDouble(site->x_num()), checkDouble(site->y_num()),
                 checkDouble(site->x_step()), checkDouble(site->y_step()));
         break;
  case defrCannotOccupyCbkType : 
         site = (defiSite*)cl;
         fprintf(fout, "CANNOTOCCUPY %s %g %g %s ",
                 site->name(), checkDouble(site->x_orig()),
                 checkDouble(site->y_orig()), site->orientStr());
         fprintf(fout, "DO %g BY %g STEP %g %g\n",
                 checkDouble(site->x_num()), checkDouble(site->y_num()),
                 checkDouble(site->x_step()), checkDouble(site->y_step()));
         break;
  case defrDieAreaCbkType :
         box = (defiBox*)cl;
         fprintf(fout, "DIEAREA");
         points = box->getPoint();
         for (i = 0; i < points.numPoints; i++)
           fprintf(fout, " %d %d", points.x[i], points.y[i]);
         fprintf(fout, "\n");
         break;
  case defrPinCapCbkType :
         pc = (defiPinCap*)cl;
         fprintf(fout, "DEFCAP MINPINS %d WIRECAP %g\n", pc->pin(),
                 checkDouble(pc->cap()));
         --numObjs;
         break;
  case defrPinCbkType :
         pin = (defiPin*)cl;
         pName = strdup((char*)pin->pinName());   // get the pinName
         // check if there has .extra<n> in the pName and ignorePE
         // is set to 1 
         if (ignorePE) {
            // check if .extra is in the name, if it is, ignore it
            if ((extraPinName = strstr(pName, ".extra")) == NULL)
               tmpPinName = pName;
            else {
               // make sure name ends with .extraNNN
               tmpName = extraPinName;
               extraPinName = extraPinName + 6;
               *tmpName = '\0';
               tmpPinName = pName;
               if (extraPinName != NULL) {
                  while (*extraPinName != '\0' && *extraPinName != '\n') {
                     if (isdigit(*extraPinName++))
                        continue;
                     else {   // Name does not end only .extraNNN
                        tmpPinName = strdup(pin->pinName());
                        break;
                     }
                  }
               }
            }
         } else
            tmpPinName = pName;
         fprintf(fout, "PIN %s + NET %s ", tmpPinName,
                 pin->netName());
         if (pin->hasDirection())
             fprintf(fout, "+ DIRECTION %s ", pin->direction());
         if (pin->hasUse())
             fprintf(fout, "+ USE %s ", pin->use());
         if (pin->hasNetExpr())
             fprintf(fout, "+ NETEXPR %s", pin->netExpr());
         if (pin->hasSupplySensitivity())
             fprintf(fout, "+ SUPPLYSENSITIVITY %s ", pin->supplySensitivity());
         if (pin->hasGroundSensitivity())
             fprintf(fout, "+ GROUNDSENSITIVITY %s ", pin->groundSensitivity());
         if (pin->hasLayer()) {
             for (i = 0; i < pin->numLayer(); i++) {
                 fprintf(fout, "+ LAYER %s ", pin->layer(i));
		 if (pin->layerMask(i)) 
                    fprintf(fout, "MASK %d ",
			    pin->layerMask(i));
                 if (pin->hasLayerSpacing(i))
                   fprintf(fout, "SPACING %d ",
                           pin->layerSpacing(i));
                 if (pin->hasLayerDesignRuleWidth(i))
                   fprintf(fout, "DESIGNRULEWIDTH %d ",
                           pin->layerDesignRuleWidth(i));
                 pin->bounds(i, &xl, &yl, &xh, &yh);
                 fprintf(fout, "( %d %d ) ( %d %d ) ", xl, yl, xh, yh);
             }
             for (i = 0; i < pin->numPolygons(); i++) {
                 fprintf(fout, "+ POLYGON %s", pin->polygonName(i));
		 if (pin->polygonMask(i))
                  fprintf(fout, "MASK %d ",
                          pin->polygonMask(i));
                 if (pin->hasPolygonSpacing(i))
                   fprintf(fout, "SPACING %d ",
                           pin->polygonSpacing(i));
                 if (pin->hasPolygonDesignRuleWidth(i))
                   fprintf(fout, "DESIGNRULEWIDTH %d ",
                           pin->polygonDesignRuleWidth(i));
                 points = pin->getPolygon(i);
                 for (k = 0; k < points.numPoints; k++)
                    fprintf(fout, " %d %d", points.x[k], points.y[k]);
             }
             for (i = 0; i < pin->numVias(); i++) {
		 if (pin->viaTopMask(i) || pin->viaCutMask(i) || pin->viaBottomMask(i)) {
                     fprintf(fout, "\nVIA %s MASK %d%d%d %d %d ", 
                         pin->viaName(i),
                         pin->viaTopMask(i),
                         pin->viaCutMask(i),
                         pin->viaBottomMask(i),
                         pin->viaPtX(i), 
                         pin->viaPtY(i));
                 } else {
		    fprintf(fout, "\nVIA %s %d %d ", pin->viaName(i),
                         pin->viaPtX(i), pin->viaPtY(i));
		 }
             }
         }
         if (pin->hasPlacement()) {
             if (pin->isPlaced())
                 fprintf(fout, " PLACED ");
             if (pin->isCover())
                 fprintf(fout, " COVER ");
             if (pin->isFixed())
                 fprintf(fout, " FIXED ");
             fprintf(fout, "( %d %d ) %s ", pin->placementX(),
                     pin->placementY(), pin->orientStr());
         }
         if (pin->hasSpecial())
             fprintf(fout, " SPECIAL ");
         fprintf(fout, "\n");

         if (pin->hasPort()) {
             struct defiPoints points;
             defiPinPort* port;
             for (j = 0; j < pin->numPorts(); j++) {
                fprintf(fout, "PIN %s", tmpPinName);
                port = pin->pinPort(j);
                fprintf(fout, " + PORT");
                for (i = 0; i < port->numLayer(); i++) {
                   fprintf(fout, "+ LAYER %s", port->layer(i));
		   if (port->layerMask(i))
                       fprintf(fout, "MASK %d ",
                               port->layerMask(i));
                   if (port->hasLayerSpacing(i))
                     fprintf(fout, " SPACING %d", port->layerSpacing(i));
                   if (port->hasLayerDesignRuleWidth(i))
                     fprintf(fout, " DESIGNRULEWIDTH %d",
                            port->layerDesignRuleWidth(i));
                   port->bounds(i, &xl, &yl, &xh, &yh);
                   fprintf(fout, " %d %d %d %d", xl, yl, xh, yh);
                }
                for (i = 0; i < port->numPolygons(); i++) {
                   fprintf(fout, " + POLYGON %s", port->polygonName(i));
		   if (port->polygonMask(i))
                     fprintf(fout, "MASK %d ",
                             port->polygonMask(i));
                   if (port->hasPolygonSpacing(i))
                     fprintf(fout, " SPACING %d", port->polygonSpacing(i));
                   if (port->hasPolygonDesignRuleWidth(i))
                     fprintf(fout, " DESIGNRULEWIDTH %d",
                            port->polygonDesignRuleWidth(i));
                   points = port->getPolygon(i);
                   for (k = 0; k < points.numPoints; k++)
                     fprintf(fout, " %d %d", points.x[k], points.y[k]);
                }
                for (i = 0; i < port->numVias(); i++) {
		   if (port->viaTopMask(i) || port->viaCutMask(i) 
                        || port->viaBottomMask(i)) {
                        fprintf(fout, "\n    VIA %s MASK %d%d%d ( %d %d ) ",
                            port->viaName(i),
                            port->viaTopMask(i),
                            port->viaCutMask(i),
                            port->viaBottomMask(i),
                            port->viaPtX(i),
                            port->viaPtY(i));
                    } else {
			fprintf(fout, " VIA %s ( %d %d ) ", port->viaName(i),
                           port->viaPtX(i), port->viaPtY(i));
		    }
                }
                if (port->hasPlacement()) {
                   if (port->isPlaced()) {
                      fprintf(fout, " + PLACED");
                      fprintf(fout, " %d %d %d ", port->placementX(),
                         port->placementY(), port->orient());
                   }
                   if (port->isCover()) {
                      fprintf(fout, " + COVER");
                      fprintf(fout, " %d %d %d ", port->placementX(),
                         port->placementY(), port->orient());
                   }
                   if (port->isFixed()) {
                      fprintf(fout, " + FIXED");
                      fprintf(fout, " %d %d %d", port->placementX(),
                         port->placementY(), port->orient());
                   }
                }
                fprintf(fout,"\n");
            }
         }
         if (pin->hasAPinPartialMetalArea()) {
             fprintf(fout, "PIN %s + NET %s ", tmpPinName,
                     pin->netName());
             for (i = 0; i < pin->numAPinPartialMetalArea(); i++) {
                 fprintf(fout, " ANTPINPARTIALMETALAREA %d ",
                         pin->APinPartialMetalArea(i));
                 if (*(pin->APinPartialMetalAreaLayer(i)))
                    fprintf(fout, " %s ", pin->APinPartialMetalAreaLayer(i));
             }
             fprintf(fout, "\n");
         }
         if (pin->hasAPinPartialMetalSideArea()) {
             fprintf(fout, "PIN %s + NET %s ", tmpPinName,
                     pin->netName());
             for (i = 0; i < pin->numAPinPartialMetalSideArea(); i++) {
                fprintf(fout, "ANTPINPARTIALMETALSIDEAREA %d",
                        pin->APinPartialMetalSideArea(i));
                if (*(pin->APinPartialMetalSideAreaLayer(i)))
                    fprintf(fout, " %s", pin->APinPartialMetalSideAreaLayer(i));
             }
             fprintf(fout, "\n");
         }
         if (pin->hasAPinPartialCutArea()) {
             fprintf(fout, "PIN %s + NET %s ", tmpPinName,
                     pin->netName());
             for (i = 0; i < pin->numAPinPartialCutArea(); i++) {
                fprintf(fout, "ANTPINPARTIALCUTAREA %d",
                        pin->APinPartialCutArea(i));
                if (*(pin->APinPartialCutAreaLayer(i)))
                    fprintf(fout, " %s", pin->APinPartialCutAreaLayer(i));
             }
             fprintf(fout, "\n");
         }
         if (pin->hasAPinDiffArea()) {
             fprintf(fout, "PIN %s + NET %s ", tmpPinName,
                     pin->netName());
             for (i = 0; i < pin->numAPinDiffArea(); i++) {
                fprintf(fout, "ANTPINDIFFAREA %d", pin->APinDiffArea(i));
                if (*(pin->APinDiffAreaLayer(i)))
                    fprintf(fout, " %s", pin->APinDiffAreaLayer(i));
             }
             fprintf(fout, "\n");
         }

         for (j = 0; j < pin->numAntennaModel(); j++) {
             aModel = pin->antennaModel(j);

             if (aModel->hasAPinGateArea()) {
                fprintf(fout, "PIN %s + NET %s %s ", tmpPinName,
                        pin->netName(), aModel->antennaOxide());
                for (i = 0; i < aModel->numAPinGateArea();
                     i++) {
                   fprintf(fout, "ANTPINGATEAREA %d", aModel->APinGateArea(i));
                   if (*(aModel->APinGateAreaLayer(i)))
                       fprintf(fout, " %s", aModel->APinGateAreaLayer(i));
                }
                fprintf(fout, "\n");
             }
             if (aModel->hasAPinMaxAreaCar()) {
                fprintf(fout, "PIN %s + NET %s %s ", tmpPinName,
                        pin->netName(), aModel->antennaOxide());
                for (i = 0; i <
                     aModel->numAPinMaxAreaCar(); i++) {
                   fprintf(fout, "ANTPINMAXAREACAR %d",
                           aModel->APinMaxAreaCar(i));
                   if (*(aModel->APinMaxAreaCarLayer(i)))
                       fprintf(fout, " %s", aModel->APinMaxAreaCarLayer(i));
                }
                fprintf(fout, "\n");
             }
             if (aModel->hasAPinMaxSideAreaCar()) {
                fprintf(fout, "PIN %s + NET %s %s ", tmpPinName,
                        pin->netName(), aModel->antennaOxide());
                for (i = 0;
                     i < aModel->numAPinMaxSideAreaCar();
                     i++) {
                   fprintf(fout, "ANTPINMAXSIDEAREACAR %d",
                           aModel->APinMaxSideAreaCar(i));
                   if (*(aModel->APinMaxSideAreaCarLayer(i)))
                       fprintf(fout, " %s", aModel->APinMaxSideAreaCarLayer(i));
                }
                fprintf(fout, "\n");
             }
             if (aModel->hasAPinMaxCutCar()) {
                fprintf(fout, "PIN %s + NET %s %s ", tmpPinName,
                        pin->netName(), aModel->antennaOxide());
                for (i = 0; i < aModel->numAPinMaxCutCar();
                     i++) {
                   fprintf(fout, "ANTPINMAXCUTCAR %d",
                           aModel->APinMaxCutCar(i));
                   if (*(aModel->APinMaxCutCarLayer(i)))
                       fprintf(fout, " %s", aModel->APinMaxCutCarLayer(i));
                }
                fprintf(fout, "\n");
             }
         }
         if (tmpPinName)
             free(tmpPinName);
         --numObjs;
         break;
  case defrDefaultCapCbkType :
         i = (long)cl;
         fprintf(fout, "DEFAULTCAP %d\n", i);
         numObjs = i;
         break;
  case defrRowCbkType :
         row = (defiRow*)cl;
         if (ignoreRN)  // PCR 716759, if flag is set don't bother with name
            fprintf(fout, "ROW %s %g %g %d",
                    row->macro(), checkDouble(row->x()), checkDouble(row->y()),
                    row->orient());
         else
            fprintf(fout, "ROW %s %s %g %g %d", row->name(),
                    row->macro(), checkDouble(row->x()), checkDouble(row->y()),
                    row->orient());
         if (row->hasDo()) {
            fprintf(fout, " DO %g BY %g",
                    checkDouble(row->xNum()), checkDouble(row->yNum()));
            if (row->hasDoStep()) 
               fprintf(fout, " STEP %g %g\n",
                       checkDouble(row->xStep()), checkDouble(row->yStep()));
         }
         fprintf(fout, "\n");
         if (row->numProps() > 0) {
            if (ignoreRN) {
                for (i = 0; i < row->numProps(); i++)
                    fprintf(fout, "ROW PROP %s %s\n",
                            row->propName(i), row->propValue(i));
            } else {
                for (i = 0; i < row->numProps(); i++)
                    fprintf(fout, "ROW %s PROP %s %s\n", row->name(),
                            row->propName(i), row->propValue(i));
            }
         }
         break;
  case defrTrackCbkType :
         track = (defiTrack*)cl;
	 /*if (track->firstTrackMask()) {
	    if (track->sameMask()) {
		fprintf(fout, "TRACKS %s %g DO %g STEP %g MASK %d SAMEMASK LAYER ",
                 track->macro(), track->x(),
                 track->xNum(), track->xStep(),
	         track->firstTrackMask());
	    } else {
		fprintf(fout, "TRACKS %s %g DO %g STEP %g MASK %d LAYER ",
                 track->macro(), track->x(),
                 track->xNum(), track->xStep(),
	         track->firstTrackMask());
	    }
	 } else {
	    fprintf(fout, "TRACKS %s %g DO %g STEP %g LAYER ",
                 track->macro(), track->x(),
                 track->xNum(), track->xStep());
	 } */
         for (i = 0; i < track->numLayers(); i++) {
	    if (track->firstTrackMask()) {
		if (track->sameMask()) {
		    fprintf(fout, "TRACKS %s %g DO %g STEP %g MASK %d SAMEMASK LAYER %s\n",
			    track->macro(), track->x(),
			    track->xNum(), track->xStep(),
			    track->firstTrackMask(), track->layer(i));
		} else {
		    fprintf(fout, "TRACKS %s %g DO %g STEP %g MASK %d LAYER %s\n",
			    track->macro(), track->x(),
			    track->xNum(), track->xStep(),
			    track->firstTrackMask(),
			    track->layer(i));
		} 
	    } else {
		    fprintf(fout, "TRACKS %s %g DO %g STEP %g LAYER %s\n",
			    track->macro(), track->x(),
			    track->xNum(), track->xStep(),
			    track->layer(i));
	    }
         }
         break;
  case defrGcellGridCbkType :
         gcg = (defiGcellGrid*)cl;
         fprintf(fout, "GCELLGRID %s %d DO %d STEP %g\n",
                 gcg->macro(), gcg->x(),
                 gcg->xNum(),
                 checkDouble(gcg->xStep()));
         break;
  case defrViaCbkType :
         via = (defiVia*)cl;
         fprintf(fout, "VIA %s ", via->name());
         if (via->hasPattern())
             fprintf(fout, " PATTERNNAME %s\n", via->pattern());
         else
             fprintf(fout, "\n");
         for (i = 0; i < via->numLayers(); i++) {
             via->layer(i, &name, &xl, &yl, &xh, &yh);
	     int rectMask = via->rectMask(i);

	     if (rectMask) {
		fprintf(fout, "VIA %s RECT %s  MASK %d ( %d %d ) ( %d %d ) \n",
                        via->name(), name, rectMask, xl, yl, xh, yh);
	     } else {
		fprintf(fout, "VIA %s RECT %s ( %d %d ) ( %d %d ) \n", via->name(),
                     name, xl, yl, xh, yh);
	     }
         }
	 // POLYGON
         if (via->numPolygons()) {
           struct defiPoints points;
           for (i = 0; i < via->numPolygons(); i++) {
	     int polyMask = via->polyMask(i);

	     if (polyMask) {
		fprintf(fout, "\n  POLYGON %s MASK %d ", 
			via->polygonName(i), polyMask);
	     } else {
                fprintf(fout, "\n  POLYGON %s ", via->polygonName(i));
	     }
             points = via->getPolygon(i);
             for (j = 0; j < points.numPoints; j++)
               fprintf(fout, "%d %d ", points.x[j], points.y[j]);
           }
           fprintf(fout, " \n");
         }

         if (via->hasViaRule()) {
             char *vrn, *bl, *cl, *tl;
             int xs, ys, xcs, ycs, xbe, ybe, xte, yte;
             int cr, cc, xo, yo, xbo, ybo, xto, yto;
             (void)via->viaRule(&vrn, &xs, &ys, &bl, &cl, &tl, &xcs,
                                         &ycs, &xbe, &ybe, &xte, &yte);
             fprintf(fout, "VIA %s VIARULE %s CUTSIZE %d %d LAYERS %s %s %s",
                     via->name(), vrn, xs, ys, bl, cl, tl);
             fprintf(fout, " CUTSPACING %d %d ENCLOSURE %d %d %d %d", xcs, ycs,
                     xbe, ybe, xte, yte);
             if (via->hasRowCol()) {
                (void)via->rowCol(&cr, &cc);
                fprintf(fout, " ROWCOL %d %d", cr, cc);
             }
             if (via->hasOrigin()) {
                (void)via->origin(&xo, &yo);
                fprintf(fout, " ORIGIN %d %d", xo, yo);
             }
             if (via->hasOffset()) {
                (void)via->offset(&xbo, &ybo, &xto, &yto);
                fprintf(fout, " OFFSET %d %d %d %d", xbo, ybo, xto, yto);
             }
             if (via->hasCutPattern())
                fprintf(fout, " PATTERN %s", via->cutPattern());
             fprintf(fout, "\n");
         }
         --numObjs;
         break;
  case defrRegionCbkType :
         re = (defiRegion*)cl;
         for (i = 0; i < re->numRectangles(); i++)
             fprintf(fout, "REGION %s ( %d %d ) ( %d %d )\n",re->name(),
                     re->xl(i), re->yl(i), re->xh(i), re->yh(i));
         if (re->hasType())
             fprintf(fout, "REGION %s TYPE %s\n",re->name(), re->type());
         --numObjs;
         break;
  case defrGroupCbkType :
         group = (defiGroup*)cl;
         fprintf(fout, "GROUP %s ", group->name());
         if (group->hasMaxX() | group->hasMaxY()
             | group->hasPerim()) {
             fprintf(fout, "SOFT ");
             if (group->hasPerim()) 
                 fprintf(fout, "MAXHALFPERIMETER %d ",
                         group->perim());
             if (group->hasMaxX())
                 fprintf(fout, "MAXX %d ", group->maxX());
             if (group->hasMaxY()) 
                 fprintf(fout, "MAXY %d ", group->maxY());
         } 
         if (group->hasRegionName())
             fprintf(fout, "REGION %s ", group->regionName());
         if (group->hasRegionBox()) {
             int *gxl, *gyl, *gxh, *gyh;
             int size;
             group->regionRects(&size, &gxl, &gyl, &gxh, &gyh);
             for (i = 0; i < size; i++)
                 fprintf(fout, "REGION (%d %d) (%d %d) ", gxl[i], gyl[i],
                         gxh[i], gyh[i]);
         }
         fprintf(fout, "\n");
         --numObjs;
         break;
  case defrComponentMaskShiftLayerCbkType :
	 fprintf(fout, "COMPONENTMASKSHIFT ");
        
        for (i = 0; i < maskShiftLayer->numMaskShiftLayers(); i++) {
           fprintf(fout, "%s ", maskShiftLayer->maskShiftLayer(i));
        } 
        fprintf(fout, ";\n");
	 break;
  case defrScanchainCbkType :
         sc = (defiScanchain*)cl;
         fprintf(fout, "SCANCHAINS %s", sc->name());
         if (sc->hasStart()) {
             sc->start(&a1, &b1);
             fprintf(fout, " START %s %s", sc->name(), a1, b1);
         }
         if (sc->hasStop()) {
             sc->stop(&a1, &b1);
             fprintf(fout, " STOP %s %s", sc->name(), a1, b1);
         }
         if (sc->hasCommonInPin() ||
             sc->hasCommonOutPin()) {
             fprintf(fout, " COMMONSCANPINS ", sc->name());
             if (sc->hasCommonInPin())
                fprintf(fout, " ( IN %s )", sc->commonInPin());
             if (sc->hasCommonOutPin())
                fprintf(fout, " ( OUT %s )",sc->commonOutPin());
         }
         fprintf(fout, "\n");
         if (sc->hasFloating()) {
            sc->floating(&size, &inst, &inPin, &outPin, &bits);
            for (i = 0; i < size; i++) {
                fprintf(fout, "SCANCHAINS %s FLOATING %s", sc->name(), inst[i]);
                if (inPin[i])
                   fprintf(fout, " IN %s", inPin[i]);
                if (outPin[i])
                   fprintf(fout, " OUT %s", outPin[i]);
                if (bits[i] != -1)
                   fprintf(fout, " BITS %d", bits[i]);
                fprintf(fout, "\n");
            }
         }

         if (sc->hasOrdered()) {
            for (i = 0; i < sc->numOrderedLists(); i++) {
                sc->ordered(i, &size, &inst, &inPin, &outPin, &bits);
                for (j = 0; j < size; j++) {
                    fprintf(fout, "SCANCHAINS %s ORDERED %s", sc->name(),
                            inst[j]); 
                    if (inPin[j])
                       fprintf(fout, " IN %s", inPin[j]);
                    if (outPin[j])
                       fprintf(fout, " OUT %s", outPin[j]);
                    if (bits[j] != -1)
                       fprintf(fout, " BITS %d", bits[j]);
                    fprintf(fout, "\n");
                }
            }
         }

         if (sc->hasPartition()) {
            fprintf(fout, "SCANCHAINS %s PARTITION %s", sc->name(),
                    sc->partitionName());
            if (sc->hasPartitionMaxBits())
              fprintf(fout, " MAXBITS %d", sc->partitionMaxBits());
         }
         fprintf(fout, "\n");
         --numObjs;
         break;
  case defrIOTimingCbkType :
         iot = (defiIOTiming*)cl;
         fprintf(fout, "IOTIMING ( %s %s )\n", iot->inst(), iot->pin());
         if (iot->hasSlewRise())
             fprintf(fout, "IOTIMING %s RISE SLEWRATE %g %g\n", iot->inst(),
                     checkDouble(iot->slewRiseMin()),
                     checkDouble(iot->slewRiseMax()));
         if (iot->hasSlewFall())
             fprintf(fout, "IOTIMING %s FALL SLEWRATE %g %g\n", iot->inst(),
                     checkDouble(iot->slewFallMin()),
                     checkDouble(iot->slewFallMax()));
         if (iot->hasVariableRise())
             fprintf(fout, "IOTIMING %s RISE VARIABLE %g %g\n", iot->inst(),
                     checkDouble(iot->variableRiseMin()),
                     checkDouble(iot->variableRiseMax()));
         if (iot->hasVariableFall())
             fprintf(fout, "IOTIMING %s FALL VARIABLE %g %g\n", iot->inst(),
                     checkDouble(iot->variableFallMin()),
                     checkDouble(iot->variableFallMax()));
         if (iot->hasCapacitance())
             fprintf(fout, "IOTIMING %s CAPACITANCE %g\n", iot->inst(),
                     checkDouble(iot->capacitance()));
         if (iot->hasDriveCell()) {
             fprintf(fout, "IOTIMING %s DRIVECELL %s ", iot->inst(),
                     iot->driveCell());
             if (iot->hasFrom())
                 fprintf(fout, " FROMPIN %s ",
                         iot->from());
             if (iot->hasTo())
                 fprintf(fout, " TOPIN %s ",
                         iot->to());
             if (iot->hasParallel())
                 fprintf(fout, "PARALLEL %g", checkDouble(iot->parallel()));
             fprintf(fout, "\n");
         }
         --numObjs;
         break;
  case defrFPCCbkType :
         fpc = (defiFPC*)cl;
         fprintf(fout, "FLOORPLAN %s ", fpc->name());
         if (fpc->isVertical())
             fprintf(fout, "VERTICAL ");
         if (fpc->isHorizontal())
             fprintf(fout, "HORIZONTAL ");
         if (fpc->hasAlign())
             fprintf(fout, "ALIGN ");
         if (fpc->hasMax())
             fprintf(fout, "%g ", checkDouble(fpc->alignMax()));
         if (fpc->hasMin())
             fprintf(fout, "%g ", checkDouble(fpc->alignMin()));
         if (fpc->hasEqual())
             fprintf(fout, "%g ", checkDouble(fpc->equal()));
         for (i = 0; i < fpc->numParts(); i++) {
             fpc->getPart(i, &corner, &typ, &name);
             if (corner == 'B')
                 fprintf(fout, "BOTTOMLEFT ");
             else
                 fprintf(fout, "TOPRIGHT ");
             if (typ == 'R')
                 fprintf(fout, "ROWS %s ", name);
             else
                 fprintf(fout, "COMPS %s ", name);
         }
         fprintf(fout, "\n");
         --numObjs;
         break;
  case defrTimingDisableCbkType :
         td = (defiTimingDisable*)cl;
         if (td->hasFromTo()) fprintf(fout, "TIMINGDISABLE FROMPIN %s %s ", td->fromInst(), td->fromPin(), td->toInst(), td->toPin()); if (td->hasThru())
             fprintf(fout, " THRUPIN %s %s ", td->thruInst(), td->thruPin());
         if (td->hasMacroFromTo())
             fprintf(fout, " MACRO %s FROMPIN %s %s ", td->macroName(),
                     td->fromPin(), td->toPin());
         if (td->hasMacroThru())
             fprintf(fout, " MACRO %s THRUPIN %s %s ", td->macroName(),
                     td->fromPin());
         fprintf(fout, "\n");
         break;
  case defrPartitionCbkType :
         part = (defiPartition*)cl;
         fprintf(fout, "PARTITION %s ", part->name());
         if (part->isSetupRise() | part->isSetupFall() | part->isHoldRise() |
             part->isHoldFall()) {
             // has turnoff 
             fprintf(fout, "TURNOFF "); 
             if (part->isSetupRise())
                 fprintf(fout, "SETUPRISE "); 
             if (part->isSetupFall())
                 fprintf(fout, "SETUPFALL "); 
             if (part->isHoldRise())
                 fprintf(fout, "HOLDRISE "); 
             if (part->isHoldFall())
                 fprintf(fout, "HOLDFALL "); 
         }
         itemT = part->itemType();
         dir = part->direction();
         if (strcmp(itemT, "CLOCK") == 0) {
             if (dir == 'T')    // toclockpin
                 fprintf(fout, " TOCLOCKPIN %s %s ", part->instName(),
                         part->pinName());
             if (dir == 'F')    // fromclockpin
                 fprintf(fout, " FROMCLOCKPIN %s %s ", part->instName(),
                         part->pinName());
             if (part->hasMin())
                 fprintf(fout, "MIN %g %g ",
                         checkDouble(part->partitionMin()),
                         checkDouble(part->partitionMax()));
             if (part->hasMax())
                 fprintf(fout, "MAX %g %g ",
                         checkDouble(part->partitionMin()),
                         checkDouble(part->partitionMax()));
             fprintf(fout, "PINS ");
             for (i = 0; i < part->numPins(); i++)
                  fprintf(fout, "%s ", part->pin(i));
         } else if (strcmp(itemT, "IO") == 0) {
             if (dir == 'T')    // toiopin
                 fprintf(fout, " TOIOPIN %s %s ", part->instName(),
                         part->pinName());
             if (dir == 'F')    // fromiopin
                 fprintf(fout, " FROMIOPIN %s %s ", part->instName(),
                         part->pinName());
         } else if (strcmp(itemT, "COMP") == 0) {
             if (dir == 'T')    // tocomppin
                 fprintf(fout, " TOCOMPPIN %s %s ", part->instName(),
                         part->pinName());
             if (dir == 'F')    // fromcomppin
                 fprintf(fout, " FROMCOMPPIN %s %s ", part->instName(),
                         part->pinName());
         }
         fprintf(fout, "\n");
         --numObjs;
         break;

  case defrPinPropCbkType :
         pprop = (defiPinProp*)cl;
         if (pprop->isPin())
            fprintf(fout, "PINPROP PIN %s ", pprop->pinName());
         else 
            fprintf(fout, "PINPROP %s %s ", pprop->instName(),
                    pprop->pinName());
         fprintf(fout, "\n");
         if (pprop->numProps() > 0) {
            for (i = 0; i < pprop->numProps(); i++) {
                fprintf(fout, "PINPROP PIN %s PROP %s %s\n",
                        pprop->pinName(), pprop->propName(i),
                        pprop->propValue(i));
            }
         }
         --numObjs;
         break;

  case defrBlockageCbkType :
         block = (defiBlockage*)cl;
         if (block->hasLayer()) {
            fprintf(fout, "BLOCKAGE LAYER %s", block->layerName());
            if (block->hasComponent())
               fprintf(fout, " COMP %s", block->layerComponentName());
            if (block->hasSlots())
               fprintf(fout, " SLOTS");
            if (block->hasFills())
               fprintf(fout, " FILLS");
            if (block->hasPushdown())
               fprintf(fout, " PUSHDOWN");
            if (block->hasExceptpgnet())
               fprintf(fout, " EXCEPTPGNET");
	    if (block->hasMask())
	       fprintf(fout, " MASK %d", block->mask());
            if (block->hasSpacing())
               fprintf(fout, " SPACING %d",
                       block->minSpacing());
            if (block->hasDesignRuleWidth())
               fprintf(fout, " DESIGNRULEWIDTH %d", block->designRuleWidth());
            fprintf(fout, "\n");
            for (i = 0; i < block->numRectangles(); i++) {
               fprintf(fout, "BLOCKAGE LAYER %s RECT %d %d %d %d\n",
                       block->layerName(), block->xl(i), block->yl(i),
                       block->xh(i), block->yh(i));
            }
            for (i = 0; i < block->numPolygons(); i++) {
               fprintf(fout, "BLOCKAGE LAYER %s POLYGON", block->layerName());
               points = block->getPolygon(i);
               for (j = 0; j < points.numPoints; j++)
                  fprintf(fout, "%d %d ", points.x[j], points.y[j]);
               fprintf(fout, "\n");
            }
         }
         else if (block->hasPlacement()) {
            fprintf(fout, "BLOCKAGE PLACEMENT");
            if (block->hasSoft())
               fprintf(fout, " SOFT");
            if (block->hasPartial())
               fprintf(fout, " PARTIAL %g", block->placementMaxDensity());
            if (block->hasComponent())
               fprintf(fout, " COMP %s", block->layerComponentName());
            if (block->hasPushdown())
               fprintf(fout, " PUSHDOWN");
            fprintf(fout, "\n");
            for (i = 0; i < block->numRectangles(); i++) {
               fprintf(fout, "BLOCKAGE PLACEMENT RECT %d %d %d %d\n",
                       block->xl(i), block->yl(i),
                       block->xh(i), block->yh(i));
            }
         }
         --numObjs;
         break;

  case defrSlotCbkType :
         slot = (defiSlot*)cl;
         for (i = 0; i < slot->numRectangles(); i++) {
            fprintf(fout, "SLOT LAYER %s", slot->layerName());
            fprintf(fout, " RECT %d %d %d %d\n",
                    slot->xl(i), slot->yl(i),
                    slot->xh(i), slot->yh(i));
         }
         for (i = 0; i < slot->numPolygons(); i++) {
            fprintf(fout, "SLOT LAYER %s POLYGON");
            points = slot->getPolygon(i);
            for (j = 0; j < points.numPoints; j++)
              fprintf(fout, " %d %d", points.x[j], points.y[j]);
            fprintf(fout, "\n");
         }
         --numObjs;
         break;

  case defrFillCbkType :
         fill = (defiFill*)cl;
         for (i = 0; i < fill->numRectangles(); i++) {
            fprintf(fout, "FILL LAYER %s", fill->layerName());
	    if (fill->layerMask()) {
                fprintf(fout, " MASK %d", fill->layerMask());
	    }
            if (fill->hasLayerOpc())
               fprintf(fout, " OPC");
            fprintf(fout, " RECT %d %d %d %d\n",
                    fill->xl(i), fill->yl(i),
                    fill->xh(i), fill->yh(i));
         }
         for (i = 0; i < fill->numPolygons(); i++) {
            fprintf(fout, "FILL LAYER %s POLYGON", fill->layerName());
            points = fill->getPolygon(i);
            for (j = 0; j < points.numPoints; j++)
              fprintf(fout, " %d %d", points.x[j], points.y[j]);
            fprintf(fout, "\n");
         }
         if (fill->hasVia()) {
            fprintf(fout, "FILL VIA %s", fill->viaName());
	    if (fill->viaTopMask() || fill->viaCutMask()
                || fill->viaBottomMask()) {
	       fprintf(fout, " MASK %d%d%d", 
		       fill->viaTopMask(),
                       fill->viaCutMask(),
                       fill->viaBottomMask());
	    }
            if (fill->hasViaOpc())
               fprintf(fout, " OPC\n");
            for (i = 0; i < fill->numViaPts(); i++) {
               points = fill->getViaPts(i);
               for (j = 0; j < points.numPoints; j++)
                 fprintf(fout, " %d %d", points.x[j], points.y[j]);
            }
            fprintf(fout, "\n");
         }
         --numObjs;
         break;

  case defrStylesCbkType :
         struct defiPoints points;
         styles = (defiStyles*)cl;
         fprintf(fout, "STYLE %d", styles->style());
         points = styles->getPolygon();
         for (j = 0; j < points.numPoints; j++)
            fprintf(fout, " %d %d", points.x[j], points.y[j]);
         fprintf(fout, "\n");
         --numObjs;
         break;

  default: fprintf(fout, "BOGUS callback to cls.\n"); return 1;
  }
  return 0;
}


int dn(defrCallbackType_e c, const char* h, defiUserData ud) {
  checkType(c);
  if (ud != userData) dataError();
  fprintf(fout, "DIVIDERCHAR \"%s\" \n",h);
  return 0;
}


int ext(defrCallbackType_e t, const char* c, defiUserData ud) {
  char* name;

  checkType(t);
  if (ud != userData) dataError();

  switch (t) {
  case defrNetExtCbkType : name = address("net"); break;
  case defrComponentExtCbkType : name = address("component"); break;
  case defrPinExtCbkType : name = address("pin"); break;
  case defrViaExtCbkType : name = address("via"); break;
  case defrNetConnectionExtCbkType : name = address("net connection"); break;
  case defrGroupExtCbkType : name = address("group"); break;
  case defrScanChainExtCbkType : name = address("scanchain"); break;
  case defrIoTimingsExtCbkType : name = address("io timing"); break;
  case defrPartitionsExtCbkType : name = address("partition"); break;
  default: name = address("BOGUS"); return 1;
  }
  fprintf(fout, "EXTENSION %s %s\n", name, c);
  return 0;
}

//========

int diffDefReadFile(char* inFile, char* outFile, char* ignorePinExtra,
                 char* ignoreRowName, char* ignoreViaName, char* netSegComp) {
  FILE* f;
  int   res;

  userData = (void*)0x01020304;
  defrInit();

  defrSetDesignCbk(dname);
  defrSetTechnologyCbk(tname);
  defrSetPropCbk(prop);
  defrSetNetCbk(netf);
  defrSetSNetCbk(snetf);
  defrSetComponentMaskShiftLayerCbk(compMSL);
  defrSetComponentCbk(compf);
  defrSetAddPathToNet();
  defrSetHistoryCbk(hist);
  defrSetConstraintCbk(constraint);
  defrSetAssertionCbk(constraint);
  defrSetDividerCbk(dn);
  defrSetBusBitCbk(bbn);
  defrSetNonDefaultCbk(ndr);

  // All of the extensions point to the same function.
  defrSetNetExtCbk(ext);
  defrSetComponentExtCbk(ext);
  defrSetPinExtCbk(ext);
  defrSetViaExtCbk(ext);
  defrSetNetConnectionExtCbk(ext);
  defrSetGroupExtCbk(ext);
  defrSetScanChainExtCbk(ext);
  defrSetIoTimingsExtCbk(ext);
  defrSetPartitionsExtCbk(ext);

  defrSetUnitsCbk(units);
  defrSetVersionCbk(vers);
  defrSetCaseSensitiveCbk(casesens);

  // The following calls are an example of using one function "cls"
  // to be the callback for many DIFFERENT types of constructs.
  // We have to cast the function type to meet the requirements
  // of each different set function.
  defrSetSiteCbk((defrSiteCbkFnType)cls);
  defrSetCanplaceCbk((defrSiteCbkFnType)cls);
  defrSetCannotOccupyCbk((defrSiteCbkFnType)cls);
  defrSetDieAreaCbk((defrBoxCbkFnType)cls);
  defrSetPinCapCbk((defrPinCapCbkFnType)cls);
  defrSetPinCbk((defrPinCbkFnType)cls);
  defrSetPinPropCbk((defrPinPropCbkFnType)cls);
  defrSetDefaultCapCbk((defrIntegerCbkFnType)cls);
  defrSetRowCbk((defrRowCbkFnType)cls);
  defrSetTrackCbk((defrTrackCbkFnType)cls);
  defrSetGcellGridCbk((defrGcellGridCbkFnType)cls);
  defrSetViaCbk((defrViaCbkFnType)cls);
  defrSetRegionCbk((defrRegionCbkFnType)cls);
  defrSetGroupCbk((defrGroupCbkFnType)cls);
  defrSetScanchainCbk((defrScanchainCbkFnType)cls);
  defrSetIOTimingCbk((defrIOTimingCbkFnType)cls);
  defrSetFPCCbk((defrFPCCbkFnType)cls);
  defrSetTimingDisableCbk((defrTimingDisableCbkFnType)cls);
  defrSetPartitionCbk((defrPartitionCbkFnType)cls);
  defrSetBlockageCbk((defrBlockageCbkFnType)cls);
  defrSetSlotCbk((defrSlotCbkFnType)cls);
  defrSetFillCbk((defrFillCbkFnType)cls);

  if (strcmp(ignorePinExtra, "0") != 0)
     ignorePE = 1;

  if (strcmp(ignoreRowName, "0") != 0)
     ignoreRN = 1;

  if (strcmp(ignoreViaName, "0") != 0)
     ignoreVN = 1;

  if (strcmp(netSegComp, "0") != 0)
     netSeCmp = 1;

  if ((f = fopen(inFile,"r")) == 0) {
    fprintf(stderr,"Couldn't open input file '%s'\n", inFile);
    return(2);
  }
 
  if ((fout = fopen(outFile, "w")) == 0) {
    fprintf(stderr, "Couldn't open output file '%s'\n", outFile);
    fclose(f);
    return(2);
  }

  res = defrRead(f, inFile, userData, 1);

  fclose(f);
  fclose(fout);

  return 0;
}
