2017-04-25 14:41:48 +02:00
|
|
|
|
/* CIFreadcell.c -
|
|
|
|
|
|
*
|
|
|
|
|
|
* This file contains more routines to parse CIF files. In
|
|
|
|
|
|
* particular, it contains the routines to handle cells,
|
|
|
|
|
|
* both definitions and calls, and user-defined features
|
|
|
|
|
|
* like labels.
|
|
|
|
|
|
*
|
|
|
|
|
|
* *********************************************************************
|
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
|
* * of the United States of America may require an export license. *
|
|
|
|
|
|
* *********************************************************************
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdcl.c,v 1.5 2010/08/25 17:33:55 tim Exp $";
|
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
|
#include "cif/CIFread.h"
|
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
|
#include "calma/calma.h"
|
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* The following variable is made available to the outside world,
|
|
|
|
|
|
* and is the cell definition currently being modified.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
CellDef *cifReadCellDef;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* The following hash table is used internally to keep track of
|
|
|
|
|
|
* of all the cells we've seen definitions for or calls on.
|
|
|
|
|
|
* The hash table entries contain pointers to cellDefs, and
|
|
|
|
|
|
* are indexed by CIF cell number. If the CDAVAILABLE bit is
|
|
|
|
|
|
* set it means we've read the cell's contents. If not set, it
|
|
|
|
|
|
* means that the cell has been called but not yet defined.
|
|
|
|
|
|
*/
|
|
|
|
|
|
HashTable CifCellTable;
|
|
|
|
|
|
|
|
|
|
|
|
/* The following variable is used to save and restore current
|
|
|
|
|
|
* paint layer information so that we can resume the correct
|
|
|
|
|
|
* layer after a subcell definition.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
Plane *cifOldReadPlane = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* The following boolean is TRUE if a subcell definition is being
|
|
|
|
|
|
* read. FALSE means we're working on the EditCell.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool cifSubcellBeingRead;
|
|
|
|
|
|
|
|
|
|
|
|
/* The following two collections of planes are used to hold CIF
|
|
|
|
|
|
* information while cells are being read in (one set for the
|
|
|
|
|
|
* outermost, unnamed cell, and one for the current subcell).
|
|
|
|
|
|
* When a cell is complete, then geometrical operations are
|
|
|
|
|
|
* performed on the layers and stuff is painted into Magic.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
Plane *cifEditCellPlanes[MAXCIFRLAYERS];
|
|
|
|
|
|
Plane *cifSubcellPlanes[MAXCIFRLAYERS];
|
|
|
|
|
|
Plane **cifCurReadPlanes = cifEditCellPlanes; /* Set of planes currently
|
|
|
|
|
|
* in force.
|
|
|
|
|
|
*/
|
|
|
|
|
|
TileType cifCurLabelType = TT_SPACE; /* Magic layer on which to put '94'
|
|
|
|
|
|
* labels that aren't identified by
|
|
|
|
|
|
* type.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* Structure used when flattening the CIF hierarchy on read-in */
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
|
Plane *plane;
|
|
|
|
|
|
Transform *trans;
|
|
|
|
|
|
} CIFCopyRec;
|
|
|
|
|
|
|
|
|
|
|
|
/* The following variable is used to hold a subcell id between
|
|
|
|
|
|
* the 91 statement and the (immediately-following?) call statement.
|
|
|
|
|
|
* The string this points to is dynamically allocated, so it must
|
|
|
|
|
|
* also be freed explicitly.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
char *cifSubcellId = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFReadCellInit --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure initializes the data structures in this
|
|
|
|
|
|
* module just prior to reading a CIF file.
|
|
|
|
|
|
*
|
|
|
|
|
|
* If ptrkeys is 0, the keys used in this hash table will
|
|
|
|
|
|
* be strings; if it is 1, the keys will be CIF numbers.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* The cell hash table is initialized, and things are set up
|
|
|
|
|
|
* to put information in the EditCell first.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
CIFReadCellInit(ptrkeys)
|
|
|
|
|
|
int ptrkeys;
|
|
|
|
|
|
{
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
HashInit(&CifCellTable, 32, ptrkeys);
|
|
|
|
|
|
cifReadCellDef = EditCellUse->cu_def;
|
|
|
|
|
|
cifSubcellBeingRead = FALSE;
|
|
|
|
|
|
cifCurReadPlanes = cifEditCellPlanes;
|
|
|
|
|
|
for (i = 0; i < MAXCIFRLAYERS; i += 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cifEditCellPlanes[i] == NULL)
|
|
|
|
|
|
cifEditCellPlanes[i] = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
|
if (cifSubcellPlanes[i] == NULL)
|
|
|
|
|
|
cifSubcellPlanes[i] = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifForgetCell --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This local procedure is used to find a cell in the subcell
|
|
|
|
|
|
* table and remove its CellDef entry.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* FALSE if no such entry was found, otherwise TRUE.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Mucks with the CIF cell name hash table.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
cifForgetCell(cifNum)
|
|
|
|
|
|
int cifNum;
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
|
|
|
|
|
|
|
h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum);
|
|
|
|
|
|
if (h == NULL)
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
else if (HashGetValue(h) == 0)
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
HashSetValue(h, 0);
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifUniqueCell --
|
|
|
|
|
|
*
|
|
|
|
|
|
* Attempt to find a cell in the CIF subcell name hash table.
|
|
|
|
|
|
* If one exists, rename its definition so that it will not
|
|
|
|
|
|
* be overwritten when the cell is redefined.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
cifUniqueCell(cifNum)
|
|
|
|
|
|
int cifNum;
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
|
CellDef *def, *testdef;
|
|
|
|
|
|
char name[17];
|
|
|
|
|
|
int reused = 0;
|
|
|
|
|
|
|
|
|
|
|
|
h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum);
|
|
|
|
|
|
|
|
|
|
|
|
if ((h == NULL) || HashGetValue(h) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Cell was deleted with "DD". Don't rename anything */
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(name, "%d", cifNum);
|
|
|
|
|
|
def = DBCellLookDef(name);
|
|
|
|
|
|
if (def == (CellDef *)NULL)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
/* Cell may have been called but not yet defined---this is okay. */
|
|
|
|
|
|
else if ((def->cd_flags & CDAVAILABLE) == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
testdef = def;
|
|
|
|
|
|
while (testdef != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
sprintf(name, "%d_%d", cifNum, ++reused);
|
|
|
|
|
|
testdef = DBCellLookDef(name);
|
|
|
|
|
|
}
|
|
|
|
|
|
DBCellRenameDef(def, name);
|
|
|
|
|
|
|
|
|
|
|
|
h = HashFind(&CifCellTable, (char *)(spointertype)cifNum);
|
|
|
|
|
|
HashSetValue(h, 0);
|
|
|
|
|
|
|
|
|
|
|
|
CIFReadError("Warning: cell definition %d reused.\n", cifNum);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifFindCell --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This local procedure is used to find a cell in the subcell
|
|
|
|
|
|
* table, and create a new subcell if there isn't already
|
|
|
|
|
|
* one there. If a new subcell is created, its CDAVAILABLE
|
|
|
|
|
|
* is left FALSE.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* The return value is a pointer to the definition for the
|
|
|
|
|
|
* cell whose CIF number is cifNum.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* A new CellDef may be created.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
CellDef *
|
|
|
|
|
|
cifFindCell(cifNum)
|
|
|
|
|
|
int cifNum; /* The CIF number of the desired cell. */
|
|
|
|
|
|
{
|
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
|
CellDef *def, *testdef;
|
|
|
|
|
|
int reused;
|
|
|
|
|
|
|
|
|
|
|
|
h = HashFind(&CifCellTable, (char *)(spointertype)cifNum);
|
|
|
|
|
|
|
|
|
|
|
|
if (HashGetValue(h) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
char name[15];
|
|
|
|
|
|
|
|
|
|
|
|
sprintf(name, "%d", cifNum);
|
|
|
|
|
|
def = DBCellLookDef(name);
|
|
|
|
|
|
if (def == NULL)
|
|
|
|
|
|
{
|
2020-03-21 17:40:35 +01:00
|
|
|
|
def = DBCellNewDef(name);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
/* Tricky point: call DBReComputeBbox here to make SURE
|
|
|
|
|
|
* that the cell has a valid bounding box. Otherwise,
|
|
|
|
|
|
* if the cell is used in a parent before being defined
|
|
|
|
|
|
* then it will cause a core dump.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
DBReComputeBbox(def);
|
|
|
|
|
|
}
|
|
|
|
|
|
HashSetValue(h, def);
|
|
|
|
|
|
}
|
|
|
|
|
|
return (CellDef *) HashGetValue(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFScalePlanes --
|
|
|
|
|
|
*
|
|
|
|
|
|
* Scale all of the CIF planes by the amount (scalen / scaled)
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
CIFScalePlanes(scalen, scaled, planearray)
|
|
|
|
|
|
int scalen;
|
|
|
|
|
|
int scaled;
|
|
|
|
|
|
Plane **planearray;
|
|
|
|
|
|
{
|
|
|
|
|
|
int pNum;
|
|
|
|
|
|
Plane *newplane;
|
|
|
|
|
|
|
|
|
|
|
|
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (planearray[pNum] != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
|
DBClearPaintPlane(newplane);
|
|
|
|
|
|
dbScalePlane(planearray[pNum], newplane, pNum,
|
|
|
|
|
|
scalen, scaled, TRUE);
|
|
|
|
|
|
DBFreePaintPlane(planearray[pNum]);
|
|
|
|
|
|
TiFreePlane(planearray[pNum]);
|
|
|
|
|
|
planearray[pNum] = newplane;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFInputRescale --
|
|
|
|
|
|
*
|
|
|
|
|
|
* Scale all CIF distances by n / d. Normally, rescaling is done in
|
|
|
|
|
|
* the upward direction (n > 1, d = 1) in response to a value in the
|
|
|
|
|
|
* CIF input that does not divide evenly into the database units of
|
|
|
|
|
|
* the CIF planes. Currently there is no call to CIFInputRescale
|
|
|
|
|
|
* with d > 1, but it is left for the possibility that scalefactors
|
|
|
|
|
|
* could be restored after finishing a subcell definition, possibly
|
|
|
|
|
|
* preventing integer overflow in large designs.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Many. Adjusts the CIF input style scalefactor (CIF vs. magic
|
|
|
|
|
|
* units), multiplier (CIF units vs. centimicrons), distances of all
|
|
|
|
|
|
* CIF boolean operations, and the scale of all existing planes in
|
|
|
|
|
|
* the current CIF database.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
CIFInputRescale(n, d)
|
|
|
|
|
|
int n, d;
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadStyle *istyle = cifCurReadStyle;
|
|
|
|
|
|
CIFReadLayer *cl;
|
|
|
|
|
|
CIFOp *op;
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
/* 2-step process for efficiency */
|
|
|
|
|
|
|
|
|
|
|
|
if (n > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
istyle->crs_scaleFactor *= n;
|
|
|
|
|
|
istyle->crs_multiplier *= n;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < istyle->crs_nLayers; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
cl = istyle->crs_layers[i];
|
|
|
|
|
|
for (op = cl->crl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
|
if (op->co_distance)
|
|
|
|
|
|
op->co_distance *= n;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (d > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
istyle->crs_scaleFactor /= d;
|
|
|
|
|
|
istyle->crs_multiplier /= d;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < istyle->crs_nLayers; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
cl = istyle->crs_layers[i];
|
|
|
|
|
|
for (op = cl->crl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
|
if (op->co_distance)
|
|
|
|
|
|
op->co_distance /= d;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CIFScalePlanes(n, d, cifEditCellPlanes);
|
|
|
|
|
|
if (cifEditCellPlanes != cifSubcellPlanes)
|
|
|
|
|
|
CIFScalePlanes(n, d, cifSubcellPlanes);
|
|
|
|
|
|
|
|
|
|
|
|
CIFReadWarning("CIF style %s: units rescaled by factor of %d / %d\n",
|
|
|
|
|
|
istyle->crs_name, n, d);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFParseStart --
|
|
|
|
|
|
*
|
|
|
|
|
|
* Parse the beginning of a symbol (cell) definition.
|
|
|
|
|
|
* ds ::= D { blank } S integer [ sep integer sep integer ]
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Set up information for the new cell, including the CIF
|
|
|
|
|
|
* planes and creating a Magic cell (if one doesn't exist
|
|
|
|
|
|
* already).
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
CIFParseStart()
|
|
|
|
|
|
{
|
|
|
|
|
|
int number;
|
|
|
|
|
|
|
|
|
|
|
|
if (cifSubcellBeingRead)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("definition start inside other definition; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (cifSubcellId != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("pending call identifier %s discarded.\n", cifSubcellId);
|
|
|
|
|
|
(void) StrDup(&cifSubcellId, (char *) NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Take the `S'. */
|
|
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
|
if (!CIFParseInteger(&number))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("definition start, but no symbol number; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (number < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("illegal negative symbol number; definition ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!CIFParseInteger(&cifReadScale1))
|
|
|
|
|
|
{
|
|
|
|
|
|
cifReadScale1 = 1;
|
|
|
|
|
|
cifReadScale2 = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
cifReadScale1 *= cifCurReadStyle->crs_multiplier; /* Units not centimicrons */
|
|
|
|
|
|
|
|
|
|
|
|
if (!CIFParseInteger(&cifReadScale2))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError(
|
|
|
|
|
|
"only one of two scale factors given; ignored.\n");
|
|
|
|
|
|
cifReadScale1 = 1;
|
|
|
|
|
|
cifReadScale2 = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (cifReadScale1 <= 0 || cifReadScale2 <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("Illegal scale %d / %d changed to 1 / 1\n",
|
|
|
|
|
|
cifReadScale1, cifReadScale2);
|
|
|
|
|
|
cifReadScale1 = 1;
|
|
|
|
|
|
cifReadScale2 = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Set up the cell definition.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
cifUniqueCell(number);
|
|
|
|
|
|
cifReadCellDef = cifFindCell(number);
|
|
|
|
|
|
DBCellClearDef(cifReadCellDef);
|
|
|
|
|
|
DBCellSetAvail(cifReadCellDef);
|
|
|
|
|
|
|
|
|
|
|
|
cifOldReadPlane = cifReadPlane;
|
|
|
|
|
|
cifReadPlane = (Plane *) NULL;
|
|
|
|
|
|
cifSubcellBeingRead = TRUE;
|
|
|
|
|
|
cifCurReadPlanes = cifSubcellPlanes;
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
* cifCheckPaintFunc ---
|
|
|
|
|
|
*
|
|
|
|
|
|
* Callback function for checking if any paint has been generated
|
|
|
|
|
|
* on the CIF target plane for a "copyup" layer.
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int cifCheckPaintFunc(tile, clientData)
|
|
|
|
|
|
Tile *tile;
|
|
|
|
|
|
ClientData clientData;
|
|
|
|
|
|
{
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Callback function for copying paint from one CIF cell into another */
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
cifCopyPaintFunc(tile, cifCopyRec)
|
|
|
|
|
|
Tile *tile;
|
|
|
|
|
|
CIFCopyRec *cifCopyRec;
|
|
|
|
|
|
{
|
|
|
|
|
|
int pNum;
|
2017-08-02 04:14:42 +02:00
|
|
|
|
TileType dinfo;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
Rect sourceRect, targetRect;
|
|
|
|
|
|
Transform *trans = cifCopyRec->trans;
|
|
|
|
|
|
Plane *plane = cifCopyRec->plane;
|
|
|
|
|
|
|
2017-08-02 04:14:42 +02:00
|
|
|
|
dinfo = TiGetTypeExact(tile);
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
TiToRect(tile, &sourceRect);
|
|
|
|
|
|
GeoTransRect(trans, &sourceRect, &targetRect);
|
2017-08-02 04:14:42 +02:00
|
|
|
|
if (IsSplit(tile))
|
|
|
|
|
|
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
TiToRect(tile, &targetRect);
|
|
|
|
|
|
|
2017-08-02 04:14:42 +02:00
|
|
|
|
DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable,
|
2017-04-25 14:41:48 +02:00
|
|
|
|
(PaintUndoInfo *)NULL);
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFPaintCurrent --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure does geometrical processing on the current
|
|
|
|
|
|
* set of CIF planes, and paints the results into the current
|
|
|
|
|
|
* CIF cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* Return 0
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Lots of information gets added to the current Magic cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CIFPaintCurrent(filetype)
|
|
|
|
|
|
bool filetype;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
2019-06-05 21:03:51 +02:00
|
|
|
|
extern int cifMakeBoundaryFunc(); /* Forward declaration. */
|
|
|
|
|
|
extern int cifPaintCurrentFunc(); /* Forward declaration. */
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
Plane *plane, *swapplane;
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
TileType type;
|
|
|
|
|
|
CIFOp *op;
|
|
|
|
|
|
|
|
|
|
|
|
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
|
|
|
|
|
&TiPlaneRect, (CellDef *) NULL, cifCurReadPlanes);
|
|
|
|
|
|
|
|
|
|
|
|
/* Generate a paint/erase table, then paint from the CIF
|
|
|
|
|
|
* plane into the current Magic cell.
|
|
|
|
|
|
*/
|
|
|
|
|
|
type = cifCurReadStyle->crs_layers[i]->crl_magicType;
|
|
|
|
|
|
|
|
|
|
|
|
if (cifCurReadStyle->crs_layers[i]->crl_flags & CIFR_TEMPLAYER)
|
|
|
|
|
|
{
|
|
|
|
|
|
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
|
|
|
|
|
while (op)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (op->co_opcode == CIFOP_COPYUP) break;
|
|
|
|
|
|
op = op->co_next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Quick check to see if anything was generated */
|
|
|
|
|
|
/* on this layer. */
|
|
|
|
|
|
|
|
|
|
|
|
if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
|
|
|
|
&DBAllButSpaceBits, cifCheckPaintFunc,
|
|
|
|
|
|
(ClientData)NULL) == 1))
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Copy-up function */
|
|
|
|
|
|
|
|
|
|
|
|
int pNum;
|
|
|
|
|
|
Plane *newplane;
|
|
|
|
|
|
Plane **parray;
|
|
|
|
|
|
extern char *(cifReadLayers[MAXCIFRLAYERS]);
|
|
|
|
|
|
|
2018-10-23 14:44:04 +02:00
|
|
|
|
/* NOTE: There should be no need to check for cd_client
|
|
|
|
|
|
* here as cd_client should not be CLIENTDEFAULT if CDFLATGDS
|
|
|
|
|
|
* is set in flags. This condition has occurred, though, and
|
|
|
|
|
|
* needs to be debugged.
|
|
|
|
|
|
*/
|
|
|
|
|
|
if ((cifReadCellDef->cd_flags & CDFLATGDS) &&
|
|
|
|
|
|
(cifReadCellDef->cd_client != (ClientData)CLIENTDEFAULT))
|
2017-04-25 14:41:48 +02:00
|
|
|
|
parray = (Plane **)cifReadCellDef->cd_client;
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
parray = (Plane **)mallocMagic(MAXCIFRLAYERS * sizeof(Plane *));
|
|
|
|
|
|
cifReadCellDef->cd_flags |= CDFLATGDS;
|
|
|
|
|
|
cifReadCellDef->cd_flags &= ~CDFLATTENED;
|
|
|
|
|
|
cifReadCellDef->cd_client = (ClientData)parray;
|
|
|
|
|
|
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
|
|
|
|
|
parray[pNum] = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (TTMaskHasType(&op->co_cifMask, pNum))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFCopyRec cifCopyRec;
|
|
|
|
|
|
|
2017-08-02 04:14:42 +02:00
|
|
|
|
newplane = parray[pNum];
|
|
|
|
|
|
if (newplane == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
|
DBClearPaintPlane(newplane);
|
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
cifCopyRec.plane = newplane;
|
|
|
|
|
|
cifCopyRec.trans = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
|
|
|
|
&DBAllButSpaceBits, cifCopyPaintFunc,
|
|
|
|
|
|
&cifCopyRec);
|
|
|
|
|
|
|
|
|
|
|
|
parray[pNum] = newplane;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-06-05 21:03:51 +02:00
|
|
|
|
else if (op == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* Handle boundary layer */
|
|
|
|
|
|
|
|
|
|
|
|
op = cifCurReadStyle->crs_layers[i]->crl_ops;
|
|
|
|
|
|
while (op)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (op->co_opcode == CIFOP_BOUNDARY) break;
|
|
|
|
|
|
op = op->co_next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
|
|
|
|
&DBAllButSpaceBits, cifCheckPaintFunc,
|
|
|
|
|
|
(ClientData)NULL) == 1))
|
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
2019-07-23 14:45:42 +02:00
|
|
|
|
&CIFSolidBits, cifMakeBoundaryFunc, (ClientData)filetype);
|
2019-06-05 21:03:51 +02:00
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
/* Swap planes */
|
|
|
|
|
|
swapplane = cifCurReadPlanes[type];
|
|
|
|
|
|
cifCurReadPlanes[type] = plane;
|
|
|
|
|
|
plane = swapplane;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
|
|
|
|
|
&CIFSolidBits, cifPaintCurrentFunc,
|
|
|
|
|
|
(ClientData)type);
|
2019-06-05 21:03:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
/* Recycle the plane, which was dynamically allocated. */
|
|
|
|
|
|
|
|
|
|
|
|
DBFreePaintPlane(plane);
|
|
|
|
|
|
TiFreePlane(plane);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Now go through all the current planes and zero them out. */
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAXCIFRLAYERS; i++)
|
|
|
|
|
|
DBClearPaintPlane(cifCurReadPlanes[i]);
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-06-05 21:03:51 +02:00
|
|
|
|
/* Use CIF layer geometry to define a fixed bounding box for the current cell */
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
cifMakeBoundaryFunc(tile, clientdata)
|
|
|
|
|
|
Tile *tile; /* Tile of CIF information. */
|
2019-07-23 14:45:42 +02:00
|
|
|
|
ClientData clientdata; /* Pass the file type (CIF or CALMA) */
|
2019-06-05 21:03:51 +02:00
|
|
|
|
{
|
|
|
|
|
|
/* It is assumed that there is one rectangle for the boundary. */
|
|
|
|
|
|
/* If there are multiple rectangles defined with the boundary */
|
|
|
|
|
|
/* layer, then the last one defines the FIXED_BBOX property. */
|
|
|
|
|
|
|
|
|
|
|
|
Rect area;
|
|
|
|
|
|
char propertyvalue[128], *storedvalue;
|
2019-07-09 02:36:48 +02:00
|
|
|
|
int savescale;
|
2019-07-23 14:45:42 +02:00
|
|
|
|
bool filetype = (bool)clientdata;
|
2019-06-05 21:03:51 +02:00
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &area);
|
2019-07-09 02:36:48 +02:00
|
|
|
|
area.r_xtop = CIFScaleCoord(area.r_xtop, COORD_EXACT);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
area.r_ytop = CIFScaleCoord(area.r_ytop, COORD_EXACT);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
|
|
|
|
|
area.r_xbot = CIFScaleCoord(area.r_xbot, COORD_EXACT);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
|
|
|
|
|
area.r_ybot = CIFScaleCoord(area.r_ybot, COORD_EXACT);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
}
|
2019-06-05 21:03:51 +02:00
|
|
|
|
|
|
|
|
|
|
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
|
2019-07-23 14:45:42 +02:00
|
|
|
|
{
|
|
|
|
|
|
char *propvalue;
|
|
|
|
|
|
bool found;
|
|
|
|
|
|
|
|
|
|
|
|
/* Only flag a warning if the redefined boundary was */
|
|
|
|
|
|
/* different from the original. */
|
|
|
|
|
|
|
|
|
|
|
|
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
|
|
|
|
|
|
if (found)
|
|
|
|
|
|
{
|
|
|
|
|
|
Rect bbox;
|
|
|
|
|
|
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
|
|
|
|
|
|
&bbox.r_xtop, &bbox.r_ytop) == 4)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((bbox.r_xbot != area.r_xbot) ||
|
|
|
|
|
|
(bbox.r_ybot != area.r_ybot) ||
|
|
|
|
|
|
(bbox.r_xtop != area.r_xtop) ||
|
|
|
|
|
|
(bbox.r_ytop != area.r_ytop))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (filetype == FILE_CIF)
|
|
|
|
|
|
CIFReadError("Warning: Cell %s boundary was redefined.\n",
|
|
|
|
|
|
cifReadCellDef->cd_name);
|
|
|
|
|
|
else
|
2019-07-25 22:29:12 +02:00
|
|
|
|
CalmaReadError("Warning: Cell %s boundary was redefined.\n",
|
2019-07-23 14:45:42 +02:00
|
|
|
|
cifReadCellDef->cd_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-06-05 21:03:51 +02:00
|
|
|
|
|
|
|
|
|
|
sprintf(propertyvalue, "%d %d %d %d",
|
|
|
|
|
|
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
|
|
|
|
|
|
storedvalue = StrDup((char **)NULL, propertyvalue);
|
|
|
|
|
|
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
|
|
|
|
|
|
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
|
2019-07-09 02:36:48 +02:00
|
|
|
|
return 0;
|
2019-06-05 21:03:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Paint CIF layer geometry into the current cell def as magic layer "type" */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
cifPaintCurrentFunc(tile, type)
|
|
|
|
|
|
Tile *tile; /* Tile of CIF information. */
|
|
|
|
|
|
TileType type; /* Magic type to be painted. */
|
|
|
|
|
|
{
|
|
|
|
|
|
Rect area;
|
|
|
|
|
|
int pNum;
|
|
|
|
|
|
int savescale;
|
|
|
|
|
|
bool snap_type = COORD_EXACT;
|
|
|
|
|
|
|
|
|
|
|
|
/* Contact types are allowed to be on half-lambda spacing, and are */
|
|
|
|
|
|
/* snapped to the nearest magic coordinate if the result is a */
|
|
|
|
|
|
/* fractional magic coordinate. */
|
|
|
|
|
|
|
|
|
|
|
|
if (DBIsContact(type)) snap_type = COORD_HALF_U;
|
|
|
|
|
|
|
|
|
|
|
|
/* Compute the area of the CIF tile, then scale it into
|
|
|
|
|
|
* Magic coordinates.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &area);
|
|
|
|
|
|
area.r_xtop = CIFScaleCoord(area.r_xtop, snap_type);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
area.r_ytop = CIFScaleCoord(area.r_ytop, snap_type);
|
|
|
|
|
|
if (snap_type == COORD_HALF_U) snap_type = COORD_HALF_L;
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
|
|
|
|
|
area.r_xbot = CIFScaleCoord(area.r_xbot, snap_type);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
|
|
|
|
|
area.r_ybot = CIFScaleCoord(area.r_ybot, snap_type);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Check for degenerate areas (from rescale limiting) before painting */
|
|
|
|
|
|
if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop))
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
|
if (DBPaintOnPlane(type, pNum))
|
|
|
|
|
|
{
|
|
|
|
|
|
DBNMPaintPlane(cifReadCellDef->cd_planes[pNum], TiGetTypeExact(tile),
|
|
|
|
|
|
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0; /* To keep the search alive. */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFParseFinish --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure is called at the end of a cell definition.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Process the CIF planes and paint the results into the Magic
|
|
|
|
|
|
* cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
CIFParseFinish()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!cifSubcellBeingRead)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("definition finish without definition start; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (cifSubcellId != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("pending call identifier %s discarded.\n", cifSubcellId);
|
|
|
|
|
|
(void) StrDup(&cifSubcellId, (char *) NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Take the `F'. */
|
|
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
|
|
|
|
|
|
|
/* Do the geometrical processing and paint this material back into
|
|
|
|
|
|
* the appropriate cell of the database. Then restore the saved
|
|
|
|
|
|
* layer info.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CIFPaintCurrent(FILE_CIF);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
DBAdjustLabels(cifReadCellDef, &TiPlaneRect);
|
|
|
|
|
|
DBReComputeBbox(cifReadCellDef);
|
|
|
|
|
|
cifReadCellDef = EditCellUse->cu_def;
|
|
|
|
|
|
cifReadPlane = cifOldReadPlane;
|
|
|
|
|
|
cifReadScale1 = 1;
|
|
|
|
|
|
cifReadScale2 = 1;
|
|
|
|
|
|
cifSubcellBeingRead = FALSE;
|
|
|
|
|
|
cifCurReadPlanes = cifEditCellPlanes;
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFParseDelete --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure is called to handle delete-symbol statements.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* The mapping between numbers and cells is modified to eliminate
|
|
|
|
|
|
* some symbols.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
CIFParseDelete()
|
|
|
|
|
|
{
|
|
|
|
|
|
int number;
|
|
|
|
|
|
|
|
|
|
|
|
/* Take the `D'. */
|
|
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
|
if (!CIFParseInteger(&number))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("definition delete, but no symbol number; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Unlink the hash entry from its target definition */
|
|
|
|
|
|
cifForgetCell(number);
|
|
|
|
|
|
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifParseName --
|
|
|
|
|
|
*
|
|
|
|
|
|
* Parse a name, which is a string of alphabetics, numerics,
|
|
|
|
|
|
* or underscores, possibly preceded by whitespace.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* The return value is a pointer to the name read from the
|
|
|
|
|
|
* CIF file. This is a statically-allocated area, so the
|
|
|
|
|
|
* caller should copy out of this area before invoking this
|
|
|
|
|
|
* procedure again.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
|
cifParseName()
|
|
|
|
|
|
{
|
|
|
|
|
|
char ch;
|
|
|
|
|
|
char *bufferp;
|
|
|
|
|
|
static char buffer[128];
|
|
|
|
|
|
|
|
|
|
|
|
/* Skip white space. */
|
|
|
|
|
|
|
|
|
|
|
|
for (ch = PEEK() ; ch == ' ' || ch == '\t' ; ch = PEEK())
|
|
|
|
|
|
TAKE();
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the string. */
|
|
|
|
|
|
|
|
|
|
|
|
bufferp = &buffer[0];
|
|
|
|
|
|
for (ch = PEEK() ; (! isspace(ch)) && ch != ';' ; ch = PEEK())
|
|
|
|
|
|
{
|
|
|
|
|
|
*bufferp++ = TAKE();
|
|
|
|
|
|
}
|
|
|
|
|
|
*bufferp = '\0';
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifParseUser9 --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure processes user extension 9: the name of the
|
|
|
|
|
|
* current symbol (cell) definition.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* The current CIF symbol is renamed from its default "cifxx" name
|
|
|
|
|
|
* to the given name.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
cifParseUser9()
|
|
|
|
|
|
{
|
|
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
|
|
|
|
name = cifParseName();
|
|
|
|
|
|
if (!DBCellRenameDef(cifReadCellDef, name))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("%s already exists, so cell from CIF is named %s.\n",
|
|
|
|
|
|
name, cifReadCellDef->cd_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFParseCall --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure processes subcell uses. The syntax of a call is
|
|
|
|
|
|
* call ::= C integer transform
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* A subcell is added to the current Magic cell we're generating.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
CIFParseCall()
|
|
|
|
|
|
{
|
|
|
|
|
|
int called;
|
|
|
|
|
|
Transform transform;
|
|
|
|
|
|
CellUse *use;
|
|
|
|
|
|
CellDef *def;
|
|
|
|
|
|
|
|
|
|
|
|
/* Take the `C'. */
|
|
|
|
|
|
|
|
|
|
|
|
TAKE();
|
|
|
|
|
|
if (!CIFParseInteger(&called))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("call, but no symbol number; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Get optional transformation. */
|
|
|
|
|
|
|
|
|
|
|
|
(void) CIFParseTransform(&transform);
|
|
|
|
|
|
|
|
|
|
|
|
def = cifFindCell(called);
|
|
|
|
|
|
|
|
|
|
|
|
/* avoid recursion
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if (DBIsAncestor(def, cifReadCellDef))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("attempt to place cell use inside its own definition!\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Find the use and add it to the current cell. Give it an
|
|
|
|
|
|
* id also.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
use = DBCellNewUse(def, cifSubcellId);
|
|
|
|
|
|
(void) DBLinkCell(use, cifReadCellDef);
|
|
|
|
|
|
DBSetTrans(use, &transform);
|
|
|
|
|
|
DBPlaceCell(use, cifReadCellDef);
|
|
|
|
|
|
|
|
|
|
|
|
(void) StrDup(&cifSubcellId, (char *) NULL);
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifParseUser91 --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure handles 91 user commands, which provide id's
|
|
|
|
|
|
* for following cell calls. The syntax is:
|
|
|
|
|
|
* 91 ::= 91 blanks name
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* The identifier is saved until the call is read. Then it is
|
|
|
|
|
|
* used as the identifier for the cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
cifParseUser91()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cifSubcellId != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("91 command with identifier %s pending; %s discarded.\n" ,
|
|
|
|
|
|
cifSubcellId , cifSubcellId);
|
|
|
|
|
|
}
|
|
|
|
|
|
(void) StrDup(&cifSubcellId, cifParseName());
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifParseUser94 --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure parses 94 user commands, which are labelled
|
|
|
|
|
|
* points. The syntax is:
|
|
|
|
|
|
* 94 ::= 94 blanks name point
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* A label is added to the current cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
cifParseUser94()
|
|
|
|
|
|
{
|
|
|
|
|
|
Rect rectangle;
|
|
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
TileType type;
|
|
|
|
|
|
int layer, flags, i;
|
|
|
|
|
|
int savescale;
|
|
|
|
|
|
|
|
|
|
|
|
(void) StrDup(&name, cifParseName());
|
|
|
|
|
|
if (! CIFParsePoint(&rectangle.r_ll, 1))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("94 command, but no location; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Scale the coordinates, then make the location into a
|
|
|
|
|
|
* rectangle.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
rectangle.r_xbot = CIFScaleCoord(rectangle.r_xbot, COORD_ANY);
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
rectangle.r_ybot = CIFScaleCoord(rectangle.r_ybot, COORD_ANY);
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
rectangle.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
|
|
|
|
|
|
rectangle.r_ur = rectangle.r_ll;
|
|
|
|
|
|
|
|
|
|
|
|
/* Get a layer, lookup the layer, then add the label to the
|
|
|
|
|
|
* current cell. Tricky business: in order for the default
|
|
|
|
|
|
* label location to be computed
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
|
if (PEEK() != ';')
|
|
|
|
|
|
{
|
|
|
|
|
|
char *lname = cifParseName();
|
|
|
|
|
|
layer = CIFReadNameToType(lname, FALSE);
|
|
|
|
|
|
if (layer < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("label attached to unknown layer %s.\n",
|
|
|
|
|
|
lname);
|
|
|
|
|
|
type = TT_SPACE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
type = cifCurReadStyle->crs_labelLayer[layer];
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
type = cifCurLabelType;
|
|
|
|
|
|
|
|
|
|
|
|
/* Should do this better, by defining cifCurLabelFlags. . . */
|
|
|
|
|
|
layer = -1;
|
|
|
|
|
|
for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
|
|
|
|
|
|
if (cifCurReadStyle->crs_labelLayer[i] == type) {
|
|
|
|
|
|
layer = i;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (type >=0 )
|
|
|
|
|
|
{
|
2017-08-02 04:14:42 +02:00
|
|
|
|
if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer])
|
2017-04-25 14:41:48 +02:00
|
|
|
|
flags = LABEL_STICKY;
|
|
|
|
|
|
else
|
|
|
|
|
|
flags = 0;
|
|
|
|
|
|
(void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags);
|
|
|
|
|
|
}
|
|
|
|
|
|
freeMagic(name);
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* cifParseUser95 --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure parses 95 user commands, which are labelled
|
|
|
|
|
|
* points. The syntax is:
|
|
|
|
|
|
* 95 ::= 95 blanks name length width point
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* An area label is added to the current cell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
cifParseUser95()
|
|
|
|
|
|
{
|
2018-08-21 04:13:16 +02:00
|
|
|
|
/* Modified by BIM 1/8/2018 */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
Rect rectangle;
|
2018-08-21 04:13:16 +02:00
|
|
|
|
Point size, center, lowerleft, upperright;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
TileType type;
|
|
|
|
|
|
int layer, i;
|
|
|
|
|
|
int savescale;
|
|
|
|
|
|
|
|
|
|
|
|
(void) StrDup(&name, cifParseName());
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
if (! CIFParsePoint(&size, 1))
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("95 command, but no size; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
|
|
|
|
|
|
/* The center coordinates returned are in CIF units *2 */
|
|
|
|
|
|
/* the values will be halved later before conversion to magic units */
|
|
|
|
|
|
|
|
|
|
|
|
if (! CIFParsePoint(¢er, 2))
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("95 command, but no location; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-21 04:13:16 +02:00
|
|
|
|
/* If reading the center causes a CIF input scale to be redefined, */
|
|
|
|
|
|
/* then the length and width must also be changed. */
|
|
|
|
|
|
|
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
|
|
|
|
|
size.p_x *= (cifCurReadStyle->crs_scaleFactor / savescale);
|
|
|
|
|
|
size.p_y *= (cifCurReadStyle->crs_scaleFactor / savescale);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
/* Scale the coordinates and create the rectangular area. */
|
2018-08-21 04:13:16 +02:00
|
|
|
|
/* Explicitly calculate lowerleft and upperright using CIF units *2 */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
/* so that half-lambda centers are resolved before remapping to */
|
|
|
|
|
|
/* magic coordinates. */
|
|
|
|
|
|
|
2018-08-21 04:13:16 +02:00
|
|
|
|
lowerleft.p_x = center.p_x - size.p_x;
|
|
|
|
|
|
lowerleft.p_y = center.p_y - size.p_y;
|
|
|
|
|
|
|
|
|
|
|
|
upperright.p_x = center.p_x + size.p_x;
|
|
|
|
|
|
upperright.p_y = center.p_y + size.p_y;
|
|
|
|
|
|
|
|
|
|
|
|
if ((lowerleft.p_x % 2 == 0) && (lowerleft.p_y % 2 == 0)) {
|
|
|
|
|
|
|
|
|
|
|
|
/* if possible convert values to CIF units by dividing by two */
|
|
|
|
|
|
|
|
|
|
|
|
lowerleft.p_x /= 2;
|
|
|
|
|
|
lowerleft.p_y /= 2;
|
|
|
|
|
|
|
|
|
|
|
|
upperright.p_x /= 2;
|
|
|
|
|
|
upperright.p_y /= 2;
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
/* if division by two would create inaccuracy then rescale to accommodate */
|
|
|
|
|
|
|
|
|
|
|
|
CIFInputRescale(2, 1);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* now scale each of the co-ordinates in turn */
|
|
|
|
|
|
|
|
|
|
|
|
lowerleft.p_x = CIFScaleCoord(lowerleft.p_x, COORD_ANY);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
lowerleft.p_y = CIFScaleCoord(lowerleft.p_y, COORD_ANY);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
2018-08-21 04:13:16 +02:00
|
|
|
|
lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
upperright.p_x = CIFScaleCoord(upperright.p_x, COORD_ANY);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
2018-08-21 04:13:16 +02:00
|
|
|
|
lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
|
}
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
upperright.p_y = CIFScaleCoord(upperright.p_y, COORD_ANY);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
|
{
|
2018-08-21 04:13:16 +02:00
|
|
|
|
lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
upperright.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
2018-08-21 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
rectangle.r_xbot = lowerleft.p_x;
|
|
|
|
|
|
rectangle.r_ybot = lowerleft.p_y;
|
|
|
|
|
|
rectangle.r_xtop = upperright.p_x;
|
|
|
|
|
|
rectangle.r_ytop = upperright.p_y;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
/* Get a layer, lookup the layer, then add the label to the
|
|
|
|
|
|
* current cell. Tricky business: in order for the default
|
|
|
|
|
|
* label location to be computed
|
|
|
|
|
|
*/
|
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
|
if (PEEK() != ';')
|
|
|
|
|
|
{
|
|
|
|
|
|
char *name = cifParseName();
|
|
|
|
|
|
layer = CIFReadNameToType(name, FALSE);
|
|
|
|
|
|
if (layer < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("label attached to unknown layer %s.\n",
|
|
|
|
|
|
name);
|
|
|
|
|
|
type = TT_SPACE;
|
|
|
|
|
|
}
|
|
|
|
|
|
else type = cifCurReadStyle->crs_labelLayer[layer];
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
type = TT_SPACE;
|
|
|
|
|
|
layer = -1;
|
|
|
|
|
|
for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
|
|
|
|
|
|
if (cifCurReadStyle->crs_labelLayer[i] == type) {
|
|
|
|
|
|
layer = i;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (type >=0 )
|
|
|
|
|
|
{
|
|
|
|
|
|
int flags;
|
2017-08-02 04:14:42 +02:00
|
|
|
|
if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer])
|
2017-04-25 14:41:48 +02:00
|
|
|
|
flags = LABEL_STICKY;
|
|
|
|
|
|
else
|
|
|
|
|
|
flags = 0;
|
|
|
|
|
|
(void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
freeMagic(name);
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFParseUser --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure is called to process user-defined statements.
|
|
|
|
|
|
* The syntax is user ::= digit usertext.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* Depends on the user command.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool
|
|
|
|
|
|
CIFParseUser()
|
|
|
|
|
|
{
|
|
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
|
|
|
|
ch = TAKE();
|
|
|
|
|
|
switch (ch)
|
|
|
|
|
|
{
|
|
|
|
|
|
case '9':
|
|
|
|
|
|
ch = PEEK();
|
|
|
|
|
|
switch (ch)
|
|
|
|
|
|
{
|
|
|
|
|
|
case '1':
|
|
|
|
|
|
(void) TAKE();
|
|
|
|
|
|
return cifParseUser91();
|
|
|
|
|
|
case '4':
|
|
|
|
|
|
(void) TAKE();
|
|
|
|
|
|
return cifParseUser94();
|
|
|
|
|
|
case '5':
|
|
|
|
|
|
(void) TAKE();
|
|
|
|
|
|
return cifParseUser95();
|
|
|
|
|
|
default:
|
|
|
|
|
|
if (isspace(ch)) return cifParseUser9();
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
CIFReadError("unimplemented user extension; ignored.\n");
|
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*
|
|
|
|
|
|
* CIFReadCellCleanup --
|
|
|
|
|
|
*
|
|
|
|
|
|
* This procedure is called after processing the CIF file.
|
|
|
|
|
|
* It performs various cleanup functions on the cells that
|
|
|
|
|
|
* have been read in.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Results:
|
|
|
|
|
|
* None.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Side effects:
|
|
|
|
|
|
* The area of each cell is DRC'ed and redisplayed. Error
|
|
|
|
|
|
* messages are output for any cells whose contents weren't
|
|
|
|
|
|
* in the CIF file. An error message is also output if
|
|
|
|
|
|
* we're still in the middle of reading a subcell.
|
|
|
|
|
|
*
|
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CIFReadCellCleanup(filetype)
|
|
|
|
|
|
bool filetype;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
|
HashSearch hs;
|
|
|
|
|
|
CellDef *def;
|
|
|
|
|
|
MagWindow *window;
|
|
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
|
|
|
|
if (cifSubcellBeingRead)
|
|
|
|
|
|
{
|
2019-07-23 14:45:42 +02:00
|
|
|
|
if (filetype == FILE_CIF)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
CIFReadError("CIF ended partway through a symbol definition.\n");
|
|
|
|
|
|
else
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CalmaReadError("GDS ended partway through a symbol definition.\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
|
(void) CIFParseFinish();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HashStartSearch(&hs);
|
|
|
|
|
|
while (TRUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
h = HashNext(&CifCellTable, &hs);
|
|
|
|
|
|
if (h == NULL) break;
|
|
|
|
|
|
|
|
|
|
|
|
def = (CellDef *) HashGetValue(h);
|
|
|
|
|
|
if (def == NULL)
|
|
|
|
|
|
{
|
2019-07-23 14:45:42 +02:00
|
|
|
|
if (filetype == FILE_CIF)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
CIFReadError("cell table has NULL entry (Magic error).\n");
|
|
|
|
|
|
else
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CalmaReadError("cell table has NULL entry (Magic error).\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
flags = def->cd_flags;
|
|
|
|
|
|
if (!(flags & CDAVAILABLE))
|
|
|
|
|
|
{
|
2019-07-23 14:45:42 +02:00
|
|
|
|
if (filetype == FILE_CIF)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
CIFReadError("cell %s was used but not defined.\n", def->cd_name);
|
|
|
|
|
|
else
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CalmaReadError("cell %s was used but not defined.\n", def->cd_name);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
def->cd_flags &= ~CDPROCESSEDGDS;
|
|
|
|
|
|
|
2019-07-23 14:45:42 +02:00
|
|
|
|
if ((filetype == FILE_CIF && CIFNoDRCCheck == FALSE) ||
|
|
|
|
|
|
(filetype == 1 && CalmaNoDRCCheck == FALSE))
|
2017-04-25 14:41:48 +02:00
|
|
|
|
DRCCheckThis(def, TT_CHECKPAINT, &def->cd_bbox);
|
|
|
|
|
|
DBWAreaChanged(def, &def->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits);
|
|
|
|
|
|
DBCellSetModified(def, TRUE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Do geometrical processing on the top-level cell. */
|
|
|
|
|
|
|
2019-07-23 14:45:42 +02:00
|
|
|
|
CIFPaintCurrent(FILE_CIF);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
|
|
|
|
|
DBReComputeBbox(EditCellUse->cu_def);
|
|
|
|
|
|
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
|
|
|
|
|
DBW_ALLWINDOWS, &DBAllButSpaceBits);
|
|
|
|
|
|
DBCellSetModified(EditCellUse->cu_def, TRUE);
|
|
|
|
|
|
|
|
|
|
|
|
/* Clean up saved CIF/GDS planes in cd_client records of cells */
|
|
|
|
|
|
|
|
|
|
|
|
HashStartSearch(&hs);
|
|
|
|
|
|
while (TRUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
h = HashNext(&CifCellTable, &hs);
|
|
|
|
|
|
if (h == NULL) break;
|
|
|
|
|
|
|
|
|
|
|
|
def = (CellDef *) HashGetValue(h);
|
|
|
|
|
|
if (def == NULL) continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (def->cd_flags & CDFLATGDS)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* These cells have been flattened and are no longer needed. */
|
|
|
|
|
|
|
|
|
|
|
|
int pNum;
|
|
|
|
|
|
Plane **cifplanes = (Plane **)def->cd_client;
|
|
|
|
|
|
|
|
|
|
|
|
UndoDisable();
|
|
|
|
|
|
|
2020-05-08 23:02:36 +02:00
|
|
|
|
/* cifplanes should be valid, but don't crash magic if not */
|
2020-05-11 02:01:05 +02:00
|
|
|
|
if (cifplanes != (Plane **)CLIENTDEFAULT)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
2020-05-08 23:02:36 +02:00
|
|
|
|
|
|
|
|
|
|
for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
{
|
2020-05-08 23:02:36 +02:00
|
|
|
|
if (cifplanes[pNum] != NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
DBFreePaintPlane(cifplanes[pNum]);
|
|
|
|
|
|
TiFreePlane(cifplanes[pNum]);
|
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
2020-05-08 23:02:36 +02:00
|
|
|
|
freeMagic((char *)def->cd_client);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
def->cd_client = (ClientData)CLIENTDEFAULT;
|
|
|
|
|
|
|
2019-11-19 17:39:59 +01:00
|
|
|
|
#if 0
|
2017-04-25 14:41:48 +02:00
|
|
|
|
/* If the CDFLATTENED flag was not set, then this geometry */
|
2019-11-19 17:39:59 +01:00
|
|
|
|
/* was never instantiated, and should generate a message. */
|
|
|
|
|
|
/* However, this is not an error condition as there are a */
|
|
|
|
|
|
/* number of useful reasons to copy lots of information up */
|
|
|
|
|
|
/* the GDS hierarchy for "just in case" scenarios. */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
if (!(def->cd_flags & CDFLATTENED))
|
2019-11-19 17:39:59 +01:00
|
|
|
|
CIFReadWarning("%s read: Unresolved geometry in cell"
|
2017-04-25 14:41:48 +02:00
|
|
|
|
" %s maps to no magic layers\n",
|
2019-07-23 14:45:42 +02:00
|
|
|
|
(filetype == FILE_CIF) ? "CIF" : "GDS", def->cd_name);
|
2019-11-19 17:39:59 +01:00
|
|
|
|
#endif
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
/* Remove the cell if it has no parents, no children, and no geometry */
|
|
|
|
|
|
/* To-do: Check that these conditions are valid */
|
|
|
|
|
|
|
|
|
|
|
|
if (def->cd_parents == (CellUse *)NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
char *savename = StrDup((char **)NULL, def->cd_name);
|
|
|
|
|
|
|
|
|
|
|
|
if (DBCellDeleteDef(def) == FALSE)
|
|
|
|
|
|
{
|
|
|
|
|
|
CIFReadError("%s read error: Unable to delete cell %s\n",
|
2019-07-23 14:45:42 +02:00
|
|
|
|
(filetype == FILE_CIF) ? "CIF" : "GDS", savename);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2019-07-23 14:45:42 +02:00
|
|
|
|
if (filetype == FILE_CIF)
|
2017-04-25 14:41:48 +02:00
|
|
|
|
TxPrintf("CIF read: Removed flattened cell %s\n", savename);
|
|
|
|
|
|
else
|
|
|
|
|
|
TxPrintf("GDS read: Removed flattened cell %s\n", savename);
|
|
|
|
|
|
}
|
|
|
|
|
|
freeMagic(savename);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
UndoEnable();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
HashKill(&CifCellTable);
|
|
|
|
|
|
}
|