/*
 * defRead.c --
 *
 * This module incorporates the LEF/DEF format for standard-cell place and
 * route.
 *
 * Version 0.1 (September 26, 2003):  DEF input of designs.
 *
 */

#ifndef lint
static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/lef/defRead.c,v 1.2 2008/06/01 18:37:43 tim Exp $";
#endif  /* not lint */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <math.h>		/* for roundf() function, if std=c99 */

#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/undo.h"
#include "utils/utils.h"
#include "utils/signals.h"
#include "database/database.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/malloc.h"
#include "graphics/graphics.h"
#include "utils/main.h"
#include "cif/cif.h"
#include "lef/lefInt.h"

/* C99 compat */
#include "textio/textio.h"
#include "commands/commands.h"

/*
 *------------------------------------------------------------
 *
 * DefAddRoutes --
 *
 *	Parse a network route statement from the DEF file,
 *	and add it to the linked list representing the route.
 *
 * Results:
 *	Returns the last token encountered.
 *
 * Side Effects:
 *	Reads from input stream;
 *	Adds information to the layout database.
 *
 *------------------------------------------------------------
 */

enum def_netspecial_keys {DEF_SPECNET_SHAPE = 0, DEF_SPECNET_STYLE,
	DEF_SPECNET_USE, DEF_SPECNET_VOLTAGE, DEF_SPECNET_FIXEDBUMP,
	DEF_SPECNET_ORIGINAL, DEF_SPECNET_PATTERN, DEF_SPECNET_ESTCAP,
	DEF_SPECNET_WEIGHT, DEF_SPECNET_PROPERTY, DEF_SPECNET_ROUTED,
	DEF_SPECNET_FIXED, DEF_SPECNET_COVER, DEF_SPECNET_SHIELD };

enum def_netspecial_shape_keys {
	DEF_SPECNET_SHAPE_RING = 0,
	DEF_SPECNET_SHAPE_PADRING,
	DEF_SPECNET_SHAPE_BLOCKRING,
	DEF_SPECNET_SHAPE_STRIPE,
	DEF_SPECNET_SHAPE_FOLLOWPIN,
	DEF_SPECNET_SHAPE_IOWIRE,
	DEF_SPECNET_SHAPE_COREWIRE,
	DEF_SPECNET_SHAPE_BLOCKWIRE,
	DEF_SPECNET_SHAPE_BLOCKAGEWIRE,
	DEF_SPECNET_SHAPE_FILLWIRE,
	DEF_SPECNET_SHAPE_FILLWIREOPC,
	DEF_SPECNET_SHAPE_DRCFILL};

const char *
DefAddRoutes(
    CellDef *rootDef,		/* Cell to paint */
    FILE *f,			/* Input file */
    float oscale,		/* Scale factor between LEF and magic units */
    bool special,		/* True if this section is SPECIALNETS */
    char *netname,		/* Name of the net, if net is to be labeled */
    LefRules *ruleset,		/* Non-default rule, or NULL */
    LefMapping *defLayerMap,	/* magic-to-lef layer mapping array */
    bool annotate)		/* If TRUE, do not generate any geometry */
{
    const char *token;
    LinkedRect *routeList, *newRoute = NULL, *routeTop = NULL;
    Point refp;			/* reference point */
    bool valid = FALSE;		/* is there a valid reference point? */
    bool initial = TRUE;
    bool labeled = TRUE;
    bool iscontact = FALSE;
    Rect locarea, r;
    int extend, lextend, hextend;
    float x, y, z, w;
    int paintWidth, saveWidth, paintExtend;
    TileType routeLayer, paintLayer;
    HashEntry *he;
    lefLayer *lefl = NULL;
    lefRule *rule = NULL;
    int keyword;

    static const char * const specnet_keys[] = {
	"SHAPE",
	"STYLE",
	"USE",
	"VOLTAGE",
	"FIXEDBUMP",
	"ORIGINAL",
	"PATTERN",
	"ESTCAP",
	"WEIGHT",
	"PROPERTY",
	"ROUTED",
	"FIXED",
	"COVER",
	"SHIELD",
	NULL
    };

    static const char * const specnet_shape_keys[] = {
	"RING",
	"PADRING",
	"BLOCKRING",
	"STRIPE",
	"FOLLOWPIN",
	"IOWIRE",
	"COREWIRE",
	"BLOCKWIRE",
	"BLOCKAGEWIRE",
	"FILLWIRE",
	"FILLWIREOPC",
	"DRCFILL",
	NULL
    };

    if (netname != NULL) labeled = FALSE;

    while (initial || (token = LefNextToken(f, TRUE)) != NULL)
    {
	/* Get next point, token "NEW", or via name */
	if (initial || !strcmp(token, "NEW") || !strcmp(token, "new"))
	{
	    /* initial pass is like a NEW record, but has no NEW keyword */
	    initial = FALSE;

	    /* invalidate reference point */
	    valid = FALSE;

	    /* assume this is not a via unless found otherwise */
	    iscontact = FALSE;

	    token = LefNextToken(f, TRUE);

	    he = HashLookOnly(&LefInfo, token);
	    if (he != NULL)
	    {
		lefl = (lefLayer *)HashGetValue(he);
		if (lefl) routeLayer = lefl->type;
	    }
	    else
	    {
		/* The fallback position is to match the DEF name to the  */
		/* magic layer name.  This is ad-hoc, and the declaration */
		/* of type mappings in the lef section of the techfile is */
		/* preferred.						  */

		routeLayer = LefHelper_DBTechNameType_LefLower(token);
		lefl = NULL;
	    }

	    if (routeLayer < 0)
	    {
		LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token);
		continue;
	    }
	    paintLayer = routeLayer;

	    if (special)
	    {
		/* SPECIALNETS has the additional width */
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%f", &w) != 1)
		{
		    LefError(DEF_ERROR, "Bad width in special net\n");
		    continue;
		}
		if (w != 0)
		    paintWidth = (int)roundf(w / oscale);
		else
		    paintWidth = (lefl) ? lefl->info.route.width :
				DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
		paintExtend = 0;	/* SPECIALNETS always have 0 wire extension */
		saveWidth = paintWidth;
	    }
	    else
	    {
		if (ruleset)
		{
		    for (rule = ruleset->rule; rule; rule = rule->next)
			if (rule->lefInfo == lefl)
			    break;
		}
		else
		    rule = NULL;

		paintWidth = (rule) ? rule->width :
				(lefl) ? lefl->info.route.width :
				DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
		paintExtend = (rule) ? rule->width : paintWidth;
	    }
	}
	else if ((*token == '+') && (special == TRUE))
	{
	    int netstyle;

	    /* Check for SHAPE, STYLE, or USE keywords */
	    token = LefNextToken(f, TRUE);
	    keyword = LookupFull(token, specnet_keys);
	    if (keyword < 0)
	    {
		LefError(DEF_INFO, "Unknown keyword \"%s\" in SPECIALNET "
			"definition; ignoring.\n", token);
		LefEndStatement(f);
		continue;
	    }
	    switch(keyword)
	    {
		case DEF_SPECNET_STYLE:
		    token = LefNextToken(f, TRUE);
		    if (sscanf(token, "%d", &netstyle) != 1)
		    {
			LefError(DEF_INFO, "Net style \"%s\" in SPECIALNET "
				    "definition is not a number; ignoring.\n", token);
			LefEndStatement(f);
			continue;
		    }
		    break;

		case DEF_SPECNET_SHAPE:
		    token = LefNextToken(f, TRUE);
		    keyword = LookupFull(token, specnet_shape_keys);
		    if (keyword < 0)
		    {
			LefError(DEF_INFO, "Unknown SHAPE \"%s\" in SPECIALNET "
				"definition; ignoring.\n", token);
			LefEndStatement(f);
			continue;
		    }
		    break;

		case DEF_SPECNET_PROPERTY:
		    /* Ignore except to absorb the next two tokens. */
		    token = LefNextToken(f, TRUE);  /* Drop through */

		case DEF_SPECNET_USE:
		case DEF_SPECNET_VOLTAGE:
		case DEF_SPECNET_ORIGINAL:
		case DEF_SPECNET_PATTERN:
		case DEF_SPECNET_ESTCAP:
		case DEF_SPECNET_WEIGHT:
		    /* Ignore except to absorb the next token. */
		    token = LefNextToken(f, TRUE);  /* Drop through */

		case DEF_SPECNET_FIXEDBUMP:
		    /* Ignore this keyword */
		    break;

		case DEF_SPECNET_SHIELD:
		    /* Treat as the following case except to absorb the next token */
		    token = LefNextToken(f, TRUE);  /* Drop through */

		case DEF_SPECNET_ROUTED:
		case DEF_SPECNET_COVER:
		case DEF_SPECNET_FIXED:
		    initial = TRUE;
		    continue;
	    }
	}
	else if (!strcmp(token, "RECT"))
	{
	    /* NOTE:  Use of "RECT" in NETS is not in the LEF/DEF spec.	*/
	    /* However, its use has been seen.	So "special" is not	*/
	    /* checked here.						*/

	    /* The rectangle coordinates are relative to the current	*/
	    /* reference point, not absolute.				*/

	    newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));

	    /* Read an (llx lly urx ury) rectangle */
	    token = LefNextToken(f, TRUE);	/* read llx */
	    if (*token == '(') token = LefNextToken(f, TRUE);
	    if (sscanf(token, "%f", &x) == 1)
	    {
		locarea.r_xbot = (refp.p_x / 2) + (int)roundf(x / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
		goto endCoord;
	    }

	    token = LefNextToken(f, TRUE);	/* read lly */
	    if (sscanf(token, "%f", &y) == 1)
	    {
		locarea.r_ybot = (refp.p_y / 2) + (int)roundf(y / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
		goto endCoord;
	    }

	    token = LefNextToken(f, TRUE);	/* read urx */
	    if (sscanf(token, "%f", &x) == 1)
	    {
		locarea.r_xtop = (refp.p_x / 2) + (int)roundf(x / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
		goto endCoord;
	    }
	    token = LefNextToken(f, TRUE);	/* read ury */
	    if (sscanf(token, "%f", &y) == 1)
	    {
		locarea.r_ytop = (refp.p_y / 2) + (int)roundf(y / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
		goto endCoord;
	    }
	    token = LefNextToken(f, TRUE);	/* read closing parens */
	    if (*token != ')')
	    {
		LefError(DEF_ERROR, "Bad coordinates in RECT.\n");
		goto endCoord;
	    }
	    GeoCanonicalRect(&locarea, &newRoute->r_r);
	}
	else if (!strcmp(token, "POLYGON"))
	{
	    LefError(DEF_ERROR, "Route has %s entries, this is not handled!\n",
			token);
	    token = LefNextToken(f, TRUE);	/* read opening parens */
	    goto endCoord;
	}
	else if (!strcmp(token, "VIRTUAL"))
	{
	    /* Is this a LEF 5.8 thing?  Not sure if it should be ignored!  */
	    /* Should the whole wire leg be ignored?			    */
	    continue;
	}
	else if (!strcmp(token, "TAPER"))
	{
	    /* Return to the default width for this layer */
	    paintWidth = (lefl) ? lefl->info.route.width :
				DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
	    paintExtend = (special) ? 0 : paintWidth;
	}
	else if (!strcmp(token, "TAPERRULE"))
	{
	    token = LefNextToken(f, TRUE);

	    he = HashLookOnly(&LefNonDefaultRules, token);
	    if (he != NULL)
	    {
	   	LefRules *tempruleset = (LefRules *)HashGetValue(he);
		for (rule = tempruleset->rule; rule; rule = rule->next)
		    if (rule->lefInfo == lefl)
			break;

		if (rule)
		{
		    paintWidth = rule->width;
		    paintExtend = rule->width;
		}
	    }
	    else if (!strcmp(token, "DEFAULT"))
	    {
	    	paintWidth = (lefl) ? lefl->info.route.width :
				DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
		paintExtend = (special) ? 0 : paintWidth;
	    }
	    else
	    	LefError(DEF_ERROR, "Unknown nondefault rule \"%s\"\n", token);
	}
	else if (*token != '(')	/* via name */
	{
	    /* A '+' or ';' record ends the route */
	    if (*token == ';' || *token == '+')
		break;

	    else if (valid == FALSE)
	    {
		LefError(DEF_ERROR, "Route has via name \"%s\" but no points!\n", token);
		continue;
	    }
	    he = HashLookOnly(&LefInfo, token);
	    if (he != NULL)
	    {
		lefl = (lefLayer *)HashGetValue(he);
		newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));

		/* The area to paint is derived from the via definitions. */

		if (lefl != NULL)
		{
		    LinkedRect *viaRoute, *addRoute;

		    /* If there is a LinkedRect structure for the via,	*/
		    /* add those records to the route first.		*/

		    for (viaRoute = lefl->info.via.lr; viaRoute != NULL;
				viaRoute = viaRoute->r_next)
		    {
			addRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
			addRoute->r_next = NULL;
			addRoute->r_type = viaRoute->r_type;
			addRoute->r_r = viaRoute->r_r;

			addRoute->r_r.r_xbot += refp.p_x;
			addRoute->r_r.r_ybot += refp.p_y;
			addRoute->r_r.r_xtop += refp.p_x;
			addRoute->r_r.r_ytop += refp.p_y;

			addRoute->r_r.r_xbot >>= 1;
			addRoute->r_r.r_ybot >>= 1;
			addRoute->r_r.r_xtop >>= 1;
			addRoute->r_r.r_ytop >>= 1;

			if (routeTop)
			    routeList->r_next = addRoute;
			else
			    routeTop = addRoute;

			routeList = addRoute;
		    }

		    paintLayer = lefl->type;

		    newRoute->r_r.r_xbot = refp.p_x + lefl->info.via.area.r_xbot;
		    newRoute->r_r.r_ybot = refp.p_y + lefl->info.via.area.r_ybot;
		    newRoute->r_r.r_xtop = refp.p_x + lefl->info.via.area.r_xtop;
		    newRoute->r_r.r_ytop = refp.p_y + lefl->info.via.area.r_ytop;

		    newRoute->r_r.r_xbot >>= 1;
		    newRoute->r_r.r_ybot >>= 1;
		    newRoute->r_r.r_xtop >>= 1;
		    newRoute->r_r.r_ytop >>= 1;

		    iscontact = TRUE;
		}
		else if ((paintLayer = LefHelper_DBTechNameType_LefLower(token)) >= 0)
		{
		    LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n",
				token);
		    newRoute->r_r.r_xbot = refp.p_x - paintWidth;
		    newRoute->r_r.r_ybot = refp.p_y - paintWidth;
		    newRoute->r_r.r_xtop = refp.p_x + paintWidth;
		    newRoute->r_r.r_ytop = refp.p_y + paintWidth;

		    newRoute->r_r.r_xbot >>= 1;
		    newRoute->r_r.r_ybot >>= 1;
		    newRoute->r_r.r_xtop >>= 1;
		    newRoute->r_r.r_ytop >>= 1;
		}
		else
		   LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);

		/* After the via, the new route layer becomes whatever	*/
		/* residue of the via was NOT the previous route layer.	*/
		/* This is absolutely impossible to make consistent	*/
		/* with the DEF	spec, but there you have it. . .	*/

		if (iscontact || (DBIsContact(paintLayer)))
		{
		    TileTypeBitMask *rMask = DBResidueMask(paintLayer);
		    TileType stype;

		    for (stype = TT_TECHDEPBASE; stype < DBNumUserLayers; stype++)
			if (TTMaskHasType(rMask, stype))
			    if (stype != routeLayer)
			    {
				/* Diagnostic */
				/*
				TxPrintf("Contact %s: In=%s Out=%s\n",
					DBTypeLongNameTbl[paintLayer],
					DBTypeLongNameTbl[routeLayer],
					DBTypeLongNameTbl[stype]);
				*/
				routeLayer = stype;

				ASSERT(routeLayer >= 0, "routeLayer<0"); /* positive bounds check */
				lefl = defLayerMap[routeLayer].lefInfo;

				/* Get correct rule for nondefault rules */
				if (ruleset)
				{
				    for (rule = ruleset->rule; rule; rule = rule->next)
					if (rule->lefInfo == lefl)
					    break;
				}
				else
				    rule = NULL;

				if (special)
				    paintWidth = saveWidth;
				else
				    paintWidth = (rule) ? rule->width :
					(lefl) ? lefl->info.route.width :
					DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];

				paintExtend = (special) ? 0 : paintWidth;
				break;
			    }
		    iscontact = FALSE;
		}
	    }
	    else
		LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);
	}
	else
	{
	    /* Revert to the routing layer type, in case we painted a via */
	    paintLayer = routeLayer;

	    /* Record current reference point */
	    locarea.r_xbot = refp.p_x;
	    locarea.r_ybot = refp.p_y;
	    lextend = extend;

	    /* Read an (X Y [extend]) point */
	    token = LefNextToken(f, TRUE);	/* read X */
	    if (*token == '*')
	    {
		if (valid == FALSE)
		{
		    LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
		    goto endCoord;
		}
	    }
	    else if (sscanf(token, "%f", &x) == 1)
	    {
		refp.p_x = (int)roundf((2 * x) / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse X coordinate.\n");
		goto endCoord;
	    }
	    token = LefNextToken(f, TRUE);	/* read Y */
	    if (*token == '*')
	    {
		if (valid == FALSE)
		{
		    LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
		    if (newRoute)
		    {
			freeMagic(newRoute);
			newRoute = NULL;
		    }
		    goto endCoord;
		}
	    }
	    else if (sscanf(token, "%f", &y) == 1)
	    {
		refp.p_y = (int)roundf((2 * y) / oscale);
	    }
	    else
	    {
		LefError(DEF_ERROR, "Cannot parse Y coordinate.\n");
		goto endCoord;
	    }

	    /* Extension is half-width for regular nets, 0 for special nets */
	    /* 0 for special nets is *not* how the 5.3 spec reads, but it   */
	    /* is apparently how everyone interprets it, and is true for    */
	    /* 5.6 spec.						    */

	    extend = paintExtend;

	    token = LefNextToken(f, TRUE);
	    if (*token != ')')
	    {
		/* non-default route extension */
		if (sscanf(token, "%f", &z) != 1)
		    LefError(DEF_ERROR, "Can't parse route extension value.\n");

		/* all values will be divided by 2, so we need	*/
		/* to multiply up by 2 now.			*/

		else
		    extend = (int)roundf((2 * z) / oscale);
	    }

	    /* Indicate that we have a valid reference point */

	    if (valid == FALSE)
	    {
		valid = TRUE;
	    }
	    else if ((locarea.r_xbot != refp.p_x) && (locarea.r_ybot != refp.p_y))
	    {
		/* Skip over nonmanhattan segments, reset the reference	*/
		/* point, and output a warning.				*/

		LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n");
		locarea.r_xbot = refp.p_x;
		locarea.r_ybot = refp.p_y;
		lextend = extend;
	    }
	    else
	    {
		newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));

		/* Route coordinates become the centerline of the	*/
		/* segment.  "refp" is kept in 1/2 lambda units so	*/
		/* we should always end up with integer units.		*/

		locarea.r_xtop = refp.p_x;
		locarea.r_ytop = refp.p_y;

		/* Change route segment to a canonical rectangle.  If	*/
		/* the route is flipped relative to canonical coords,	*/
		/* then the wire extentions have to be swapped as well.	*/

		if ((locarea.r_xtop < locarea.r_xbot) ||
			(locarea.r_ytop < locarea.r_ybot))
		{
		    hextend = lextend;
		    lextend = extend;
		}
		else
		    hextend = extend;

		GeoCanonicalRect(&locarea, &newRoute->r_r);

		if (newRoute->r_r.r_xbot == newRoute->r_r.r_xtop)
		{
		    newRoute->r_r.r_xbot -= paintWidth;
		    newRoute->r_r.r_xtop += paintWidth;
		}
		else
		{
		    newRoute->r_r.r_xbot -= lextend;
		    newRoute->r_r.r_xtop += hextend;
		}

		if (newRoute->r_r.r_ybot == newRoute->r_r.r_ytop)
		{
		    newRoute->r_r.r_ybot -= paintWidth;
		    newRoute->r_r.r_ytop += paintWidth;
		}
		else
		{
		    newRoute->r_r.r_ybot -= lextend;
		    newRoute->r_r.r_ytop += hextend;
		}

		/* If we don't have integer units here, we should	*/
		/* rescale the magic internal grid.			*/

		newRoute->r_r.r_xbot >>= 1;
		newRoute->r_r.r_ybot >>= 1;
		newRoute->r_r.r_xtop >>= 1;
		newRoute->r_r.r_ytop >>= 1;
	    }

endCoord:
	    /* Find the closing parenthesis for the coordinate pair */
	    while (*token != ')')
		token = LefNextToken(f, TRUE);
	}

	/* Link in the new route segment */
	if (newRoute)
	{
	    newRoute->r_type = paintLayer;
	    newRoute->r_next = NULL;

	    if (routeTop)
		routeList->r_next = newRoute;
	    else
		routeTop = newRoute;

	    routeList = newRoute;
	    newRoute = NULL;
	}
    }

    /* Process each segment and paint into the layout */

    free_magic1_t mm1 = freeMagic1_init();
    while (routeTop != NULL)
    {
	/* paint */
	if (annotate == FALSE)
	{
	    DBPaint(rootDef, &routeTop->r_r, routeTop->r_type);

	    /* label */
	    if (labeled == FALSE)
	    {
		r.r_xbot = r.r_xtop = (routeTop->r_r.r_xbot + routeTop->r_r.r_xtop) / 2;
		r.r_ybot = r.r_ytop = (routeTop->r_r.r_ybot + routeTop->r_r.r_ytop) / 2;
		DBPutLabel(rootDef, &r, GEO_CENTER, netname, routeTop->r_type, 0, 0);
		labeled = TRUE;
	    }
	}
	else
	{
	    /* When annotating, make sure there is a valid layer under the	*/
	    /* label.  If not, then wait for the next bit of geometry.		*/

	    if (labeled == FALSE)
	    {
		Tile *tp;
		Plane *plane = rootDef->cd_planes[DBPlane(routeTop->r_type)];
		tp = PlaneGetHint(plane);
		GOTOPOINT(tp, &routeTop->r_r.r_ll);
		if (TiGetType(tp) == routeTop->r_type)
		{
		    r.r_xbot = r.r_xtop =
				(routeTop->r_r.r_xbot + routeTop->r_r.r_xtop) / 2;
		    r.r_ybot = r.r_ytop =
				(routeTop->r_r.r_ybot + routeTop->r_r.r_ytop) / 2;
		    DBPutLabel(rootDef, &r, GEO_CENTER, netname, routeTop->r_type,
				0, 0);
		    labeled = TRUE;
		}
		if ((labeled == FALSE) && (routeTop->r_next == NULL))
		{
		    TxError("Warning:  Label \"%s\" did not land on any existing"
				" net geometry.\n", netname);
		    r.r_xbot = r.r_xtop =
				(routeTop->r_r.r_xbot + routeTop->r_r.r_xtop) / 2;
		    r.r_ybot = r.r_ytop =
				(routeTop->r_r.r_ybot + routeTop->r_r.r_ytop) / 2;
		    DBPutLabel(rootDef, &r, GEO_CENTER, netname, routeTop->r_type,
				0, 0);
		    labeled = TRUE;
		}
	    }
	}

	/* advance to next point and free record (1-delayed) */
	freeMagic1(&mm1, (char *)routeTop);
	routeTop = routeTop->r_next;
    }
    freeMagic1_end(&mm1);
    return token;	/* Pass back the last token found */
}

/*
 *------------------------------------------------------------
 *
 * DefReadNonDefaultRules --
 *
 *	Read a NONDEFAULTRULES section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Adds information into the non-default rules hash table.
 *
 *------------------------------------------------------------
 */

enum def_nondef_keys {DEF_NONDEF_START = 0, DEF_NONDEF_END};
enum def_nondefprop_keys {
	DEF_NONDEFPROP_HARDSPACING = 0, DEF_NONDEFPROP_LAYER,
	DEF_NONDEFPROP_VIA, DEF_NONDEFPROP_VIARULE,
	DEF_NONDEFPROP_MINCUTS, DEF_NONDEFPROP_PROPERTY,
	DEF_NONDEFLAYER_WIDTH, DEF_NONDEFLAYER_DIAG,
	DEF_NONDEFLAYER_SPACE, DEF_NONDEFLAYER_EXT,
	DEF_NONDEFPROP_DONE};

void
DefReadNonDefaultRules(
    FILE *f,
    CellDef *rootDef,
    const char *sname,
    float oscale,
    int total)
{
    const char *token;
    int keyword, subkey;
    int processed = 0;
    HashEntry *he;
    lefLayer *lefl;
    float fvalue;
    LefRules *ruleset = NULL;
    lefRule *rule = NULL;
    bool inlayer;

    static const char * const nondef_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const nondef_property_keys[] = {
	"HARDSPACING",
	"LAYER",
	"VIA",
	"VIARULE",
	"MINCUTS",
	"PROPERTY",
	"WIDTH",
	"DIAGWIDTH",
	"SPACING",
	"WIREEXT",
	";",
	NULL
    };

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, nondef_keys);
	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in NONDEFAULTRULES "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}

	switch (keyword)
	{
	    case DEF_NONDEF_START:

		/* Get non-default rule name */
		token = LefNextToken(f, TRUE);

		/* Create a hash entry for this nondefault rule */
		/* NOTE:  Needs to handle name collisions.	*/
		he = HashFind(&LefNonDefaultRules, token);
		ruleset = (LefRules *)mallocMagic(sizeof(LefRules));
		HashSetValue(he, ruleset);
		ruleset->name = StrDup((char **)NULL, token);
		ruleset->rule = NULL;
		processed++;

		/* Process all properties */
		while (token && (*token != ';'))
		{
		    if (*token != '+')
		    {
			token = LefNextToken(f, TRUE);
			if (!inlayer)
			    continue;
		    }
		    if (*token == '+')
		    {
			inlayer = FALSE;
			rule = NULL;
			token = LefNextToken(f, TRUE);
		    }

		    subkey = LookupFull(token, nondef_property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown non-default rule property \"%s\" "
				"in NONDEFAULTRULE definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_NONDEFPROP_DONE:
			    break;
			case DEF_NONDEFPROP_HARDSPACING:
			    lefl = NULL;
			    /* Ignore this */
			    break;
			case DEF_NONDEFPROP_VIA:
			case DEF_NONDEFPROP_VIARULE:
			    lefl = NULL;
			    /* Fall through */
			case DEF_NONDEFPROP_LAYER:
			    token = LefNextToken(f, TRUE);
			    he = HashFind(&LefInfo, token);
			    lefl = (lefLayer *)HashGetValue(he);
			    if (ruleset)
			    {
				/* Chain new layer rule to linked list */
				rule = (lefRule *)mallocMagic(sizeof(lefRule));
			    	rule->lefInfo = lefl;
				rule->width = 0;
				rule->spacing = 0;
				rule->extend = 0;		/* unused */
				rule->next = ruleset->rule;
				ruleset->rule = rule;
			    }
			    else
				LefError(DEF_INFO, "No non-default rule name for \"%s\" "
					"in NONDEFAULTRULE definition!.\n", token);
			    if (subkey == DEF_NONDEFPROP_LAYER) inlayer = TRUE;
			    break;
			case DEF_NONDEFPROP_MINCUTS:
			case DEF_NONDEFPROP_PROPERTY:
			    lefl = NULL;
			    /* Ignore the next two tokens */
			    token = LefNextToken(f, TRUE);
			    token = LefNextToken(f, TRUE);
			    break;
			case DEF_NONDEFLAYER_WIDTH:
			    if (!inlayer)
				LefError(DEF_INFO, "WIDTH specified without layer.\n");
			    token = LefNextToken(f, TRUE);
			    sscanf(token, "%f", &fvalue);
			    if (rule == NULL)
				LefError(DEF_INFO, "No rule for non-default width.\n");
			    else if (lefl == NULL)
				LefError(DEF_INFO, "No layer for non-default width.\n");
			    else
			    	rule->width = (int)roundf(fvalue / oscale);
			    break;
			case DEF_NONDEFLAYER_SPACE:
			    if (!inlayer)
				LefError(DEF_INFO, "SPACING specified without layer.\n");
			    token = LefNextToken(f, TRUE);
			    sscanf(token, "%f", &fvalue);
			    if (rule == NULL)
				LefError(DEF_INFO, "No rule for non-default spacing.\n");
			    else if (lefl == NULL)
				LefError(DEF_INFO, "No layer for non-default spacing.\n");
			    else
			    	rule->spacing = (int)roundf(fvalue / oscale);
			    break;
			case DEF_NONDEFLAYER_EXT:
			    if (!inlayer)
				LefError(DEF_INFO, "WIREEXT specified without layer.\n");
			    token = LefNextToken(f, TRUE);
			    sscanf(token, "%f", &fvalue);
			    if (rule == NULL)
				LefError(DEF_INFO, "No rule for non-default extension.\n");
			    else if (lefl == NULL)
				LefError(DEF_INFO, "No layer for non-default extension.\n");
			    else
			    {
				LefError(DEF_WARNING, "Non-default extension at via not implemented.\n");
			    	rule->extend = (int)roundf((2 * fvalue) / oscale);
			    }
			    break;
			case DEF_NONDEFLAYER_DIAG:
			    if (!inlayer)
				LefError(DEF_INFO,
					"Layer value specified without layer.\n");
			    /* Absorb token and ignore */
			    token = LefNextToken(f, TRUE);
			    break;
		    }
		}
		inlayer = FALSE;
		break;

	    case DEF_NONDEF_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Non-default rule END statement missing.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_NONDEF_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d non-default rules total.\n", processed);
    else
	LefError(DEF_WARNING, "Number of non-default rules read (%d) does not match "
		"the number declared (%d).\n", processed, total);
}

/*
 *------------------------------------------------------------
 *
 * defFoundOneFunc --
 *
 *	Simple callback function for DefReadNets() when using
 *	the "def read -annoatate" option.  Attempts to find
 *	paint in the top level in the area of a pin that is
 *	part of the net.
 *
 *	Note:  The routine does not search on connected tiles
 *	and so could miss the connecting material, although
 *	there are multiple fall-back chances to succeed.
 * 
 * Returns:
 *	1 to stop the search, as we just take the first tile
 *	found and run with it.
 *
 * Side effects:
 *	Copies a pointer to the tile found into the client
 *	data record.
 *
 *------------------------------------------------------------
 */

int
defFoundOneFunc(
    Tile *tile,
    TileType dinfo,	/* (unused) */
    Tile **tret)
{
    *tret = tile;
    return 1;
}

/*
 *------------------------------------------------------------
 *
 * DefReadNets --
 *
 *	Read a NETS or SPECIALNETS section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Many.  Networks are created, and geometry may be
 *	painted into the database top-level cell.
 *
 *------------------------------------------------------------
 */

enum def_net_keys {DEF_NET_START = 0, DEF_NET_END};
enum def_netprop_keys {
	DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_NOSHIELD,
	DEF_NETPROP_FIXED, DEF_NETPROP_COVER, DEF_NETPROP_SOURCE,
	DEF_NETPROP_SHIELDNET, DEF_NETPROP_SUBNET, DEF_NETPROP_VPIN,
	DEF_NETPROP_XTALK, DEF_NETPROP_NONDEFRULE, DEF_NETPROP_FIXEDBUMP,
	DEF_NETPROP_FREQUENCY, DEF_NETPROP_ORIGINAL, DEF_NETPROP_PATTERN,
	DEF_NETPROP_ESTCAP, DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY
};

void
DefReadNets(
    FILE *f,
    CellDef *rootDef,
    const char *sname,
    float oscale,
    bool special,		/* True if this section is SPECIALNETS */
    bool dolabels,		/* If true, create a label for each net */
    bool annotate,		/* If true, create labels, not geometry */
    int total)
{
    const char *token;
    char *netname = NULL, *prnet;
    int keyword, subkey;
    int processed = 0;
    LefMapping *defLayerMap;
    LefRules *ruleset = NULL;
    HashEntry *he;
    bool needanno;

    static const char * const net_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const net_property_keys[] = {
	"USE",
	"ROUTED",
	"NOSHIELD",
	"FIXED",
	"COVER",
	"SOURCE",
	"SHIELDNET",
	"SUBNET",
	"VPIN",
	"XTALK",
	"NONDEFAULTRULE",
	"FIXEDBUMP",
	"FREQUENCY",
	"ORIGINAL",
	"PATTERN",
	"ESTCAP",
	"WEIGHT",
	"PROPERTY",
	NULL
    };

    defLayerMap = defMakeInverseLayerMap(LAYER_MAP_VIAS);

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, net_keys);
	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in NET "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}

	switch (keyword)
	{
	    case DEF_NET_START:

		/* Get net name */
		token = LefNextToken(f, TRUE);
		if (dolabels) netname = StrDup((char **)NULL, token);
		needanno = annotate;

		/* Any nondefault rule resets at the start of a new net. */
		ruleset = (LefRules *)NULL;

		/* Update the record of the number of nets processed	*/
		/* and spit out a message for every 5% finished.	*/

		LefEstimate(processed++, total,
			(special) ? "special nets" : "nets");

		/* Process all properties */
		while (token && (*token != ';'))
		{
		    if (needanno)
		    {
			char *compname, *termname;

			/* Annotation only---when back-annotating	*/
			/* labels into a layout, the safest place to	*/
			/* put labels is on a terminal position		*/

			if (*token == '(')
			{
			    token = LefNextToken(f, TRUE);
			    if (!strcmp(token, "PIN"))
				needanno = FALSE;
			    else
			    {
				Rect r;
				bool isvalid;
				TileType ttype;
				Tile *tp;

				compname = StrDup((char **)NULL, token);
			    	token = LefNextToken(f, TRUE);
				termname = (char *)mallocMagic(strlen(compname) +
					strlen(token) + 3);
				sprintf(termname, "%s/%s", compname, token);
				ttype = CmdFindNetProc(termname, EditCellUse, &r,
					FALSE, &isvalid);
				if (isvalid)
				{
				    /* The pin was found.  However, there may not be
				     * paint on the top level over the whole pin.
				     * Search the area (+1) for attached paint, then
				     * label inside that tile.
				     */
				    tp = NULL;
				    DBSrPaintArea((Tile *)NULL,
						rootDef->cd_planes[DBPlane(ttype)],
						&r, &DBConnectTbl[ttype],
						defFoundOneFunc, (ClientData)&tp);

				    if (tp != NULL)
				    {
					TiToRect(tp, &r);
					r.r_xbot = r.r_xtop = (r.r_xbot + r.r_xtop) / 2;
					r.r_ybot = r.r_ytop = (r.r_ybot + r.r_ytop) / 2;
					DBPutLabel(rootDef, &r, GEO_CENTER, netname,
						ttype, 0, 0);
					needanno = FALSE;
				    }
				}
				freeMagic(termname);
				freeMagic(compname);
			    }
			}
		    }

		    /* All connections are ignored, and we go		*/
		    /* go directly to the first property ("+") key	*/

		    if (*token != '+')
		    {
			token = LefNextToken(f, TRUE);
			continue;
		    }
		    else
			token = LefNextToken(f, TRUE);

		    subkey = LookupFull(token, net_property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown net property \"%s\" in "
				"NET definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_NETPROP_ROUTED:
			case DEF_NETPROP_FIXED:
			case DEF_NETPROP_COVER:
			case DEF_NETPROP_NOSHIELD:
			    prnet = NULL;
			    if (dolabels && (needanno || (!annotate)))
				prnet = netname;
			    token = DefAddRoutes(rootDef, f, oscale, special,
					prnet, ruleset, defLayerMap, annotate);
			    ruleset = NULL;
			    break;

			case DEF_NETPROP_NONDEFRULE:
		    	    token = LefNextToken(f, TRUE);
			    /*
			     * Differs from "TAPERRULE" in that it specifies a non-default
			     * rule to use for the entire net.
			     */
			    he = HashLookOnly(&LefNonDefaultRules, token);
			    if (he != NULL)
			        ruleset = (LefRules *)HashGetValue(he);
			    else
			    	LefError(DEF_ERROR, "Unknown nondefault rule \"%s\"\n", token);
			    break;

			case DEF_NETPROP_PROPERTY:
			    /* Ignore except to absorb the next two tokens. */
			    token = LefNextToken(f, TRUE);  /* Drop through */

			case DEF_NETPROP_SOURCE:
			case DEF_NETPROP_USE:
			case DEF_NETPROP_SHIELDNET:
			case DEF_NETPROP_SUBNET:
			case DEF_NETPROP_XTALK:
			case DEF_NETPROP_FREQUENCY:
			case DEF_NETPROP_ORIGINAL:
			case DEF_NETPROP_PATTERN:
			case DEF_NETPROP_ESTCAP:
			case DEF_NETPROP_WEIGHT:
			    /* Ignore except to absorb the next token. */
			    token = LefNextToken(f, TRUE);  /* Drop through */

			case DEF_NETPROP_FIXEDBUMP:
			    /* Ignore this keyword */
			    break;

			case DEF_NETPROP_VPIN:
			    /* VPIN is an in-line pin not in the PINS section	*/
			    /* Need to handle this!				*/
			    token = LefNextToken(f, TRUE);
			    break;
		    }
		}
		if (dolabels) freeMagic(netname);
		break;

	    case DEF_NET_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Net END statement missing.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_NET_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d%s nets total.\n", processed,
		(special) ? " special" : "");
    else
	LefError(DEF_WARNING, "Number of nets read (%d) does not match "
		"the number declared (%d).\n", processed, total);

    freeMagic((char *)defLayerMap);
}

/*
 *------------------------------------------------------------
 *
 * DefReadUseLocation --
 *
 *	Read location and orientation of a cell use
 *	Syntax: ( X Y ) O
 *
 * Results:
 *	0 on success, -1 on failure
 *
 * Side Effects:
 *	Transform is placed in the location pointed to by "tptr".
 *	This routine can be used for placement of geometry (as
 *	opposed to cell uses) by setting "use" to NULL, and using
 *	the resulting transform to modify the geometry.
 *------------------------------------------------------------
 */
enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST,
	DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST,
	DEF_FLIPPED_WEST};

int
DefReadLocation(
    CellUse *use,
    FILE *f,
    float oscale,
    Transform *tptr,
    bool noplace)
{
    const Rect *r;
    Rect tr, rect;
    int keyword;
    const char *token;
    float x, y;
    Transform t2;

    static const char * const orientations[] = {
	"N", "S", "E", "W", "FN", "FS", "FE", "FW"
    };

    if (noplace)
    {
	LefError(DEF_WARNING, "Unplaced component \"%s\" will be put at origin.\n",
		    use->cu_id);
	x = 0;
	y = 0;
	keyword = DEF_NORTH;
    }
    else
    {
        token = LefNextToken(f, TRUE);
        if (*token != '(') goto parse_error;
        token = LefNextToken(f, TRUE);
        if (sscanf(token, "%f", &x) != 1) goto parse_error;
        token = LefNextToken(f, TRUE);
        if (sscanf(token, "%f", &y) != 1) goto parse_error;
        token = LefNextToken(f, TRUE);
        if (*token != ')') goto parse_error;
        token = LefNextToken(f, TRUE);

        keyword = LookupFull(token, orientations);
        if (keyword < 0)
        {
	    LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
	    return -1;
	}
    }

    /* The standard transformations are all defined to rotate	*/
    /* or flip about the origin.  However, DEF defines them	*/
    /* around the center such that the lower left corner is	*/
    /* unchanged after the transformation.  Case conditions	*/
    /* restore the lower-left corner position.			*/

    if (use)
    {
	r = &use->cu_def->cd_bbox;

	/* Abstract views with fixed bounding boxes use the FIXED_BBOX property */

	if (use->cu_def->cd_flags & CDFIXEDBBOX)
	{
	    PropertyRecord *proprec;
	    bool found;

	    proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
	    if (found)
	    {
		if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
			(proprec->prop_len == 4))
		{
		    rect.r_xbot = proprec->prop_value.prop_integer[0];
		    rect.r_ybot = proprec->prop_value.prop_integer[1];
		    rect.r_xtop = proprec->prop_value.prop_integer[2];
		    rect.r_ytop = proprec->prop_value.prop_integer[3];
		    r = &rect;
		}
	    }
	}
    }
    else
	r = &GeoNullRect;

    switch (keyword)
    {
	case DEF_NORTH:
	    *tptr = GeoIdentityTransform;
	    break;
	case DEF_SOUTH:
	    *tptr = Geo180Transform;
	    break;
	case DEF_EAST:
	    *tptr = Geo90Transform;
	    break;
	case DEF_WEST:
	    *tptr = Geo270Transform;
	    break;
	case DEF_FLIPPED_NORTH:
	    *tptr = GeoSidewaysTransform;
	    break;
	case DEF_FLIPPED_SOUTH:
	    *tptr = GeoUpsideDownTransform;
	    break;
	case DEF_FLIPPED_EAST:
	    *tptr = GeoRef135Transform;
	    break;
	case DEF_FLIPPED_WEST:
	    *tptr = GeoRef45Transform;
	    break;
    }
    GeoTransRect(tptr, r, &tr);
    GeoTranslateTrans(tptr, -tr.r_xbot, -tr.r_ybot, &t2);
    GeoTranslateTrans(&t2, (int)roundf(x / oscale), (int)roundf(y / oscale), tptr);
    if (use)
	DBSetTrans(use, tptr);
    return 0;

parse_error:
    LefError(DEF_ERROR, "Cannot parse location: must be ( X Y ) orient\n");
    return -1;
}

/*
 *------------------------------------------------------------
 *
 * DefReadPins --
 *
 *	Read a PINS section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Generates paint and labels in the layout.
 *
 *------------------------------------------------------------
 */

enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END};
enum def_pins_prop_keys {
	DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR,
	DEF_PINS_PROP_LAYER, DEF_PINS_PROP_USE,
	DEF_PINS_PROP_PLACED, DEF_PINS_PROP_FIXED,
	DEF_PINS_PROP_COVER, DEF_PINS_PROP_PORT,
	DEF_PINS_PROP_SPECIAL};

void
DefReadPins(
    FILE *f,
    CellDef *rootDef,
    const char *sname,
    float oscale,
    int total,
    bool annotate)
{
    const char *token;
    char pinname[LEF_LINE_MAX];
    int keyword, subkey, flags;
    int processed = 0;
    int pinDir = PORT_CLASS_DEFAULT;
    int pinUse = PORT_USE_DEFAULT;
    int pinNum = 0;
    int width, height, rot, size;
    TileType curlayer = -1;
    LinkedRect *rectList = NULL, *newRect;
    Rect *currect, topRect;
    Transform t;
    bool pending = FALSE;
    bool hasports = FALSE;

    static const char * const pin_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const pin_property_keys[] = {
	"NET",
	"DIRECTION",
	"LAYER",
	"USE",
	"PLACED",
	"FIXED",
	"COVER",
	"PORT",
	"SPECIAL",
	NULL
    };

    static const char * const pin_classes[] = {
	"DEFAULT",
	"INPUT",
	"OUTPUT TRISTATE",
	"OUTPUT",
	"INOUT",
	"FEEDTHRU",
	NULL
    };

    static const char * const pin_uses[] = {
	"DEFAULT",
	"SIGNAL",
	"POWER",
	"GROUND",
	"CLOCK",
	"RESET",
	"ANALOG",
	"SCAN",
	"TIEOFF",
	NULL
    };

    static const int lef_class_to_bitmask[] = {
	PORT_CLASS_DEFAULT,
	PORT_CLASS_INPUT,
	PORT_CLASS_TRISTATE,
	PORT_CLASS_OUTPUT,
	PORT_CLASS_BIDIRECTIONAL,
	PORT_CLASS_FEEDTHROUGH
    };

    static const int lef_use_to_bitmask[] = {
	PORT_USE_DEFAULT,
	PORT_USE_SIGNAL,
	PORT_USE_POWER,
	PORT_USE_GROUND,
	PORT_USE_CLOCK,
	PORT_USE_RESET,
	PORT_USE_ANALOG,
	PORT_USE_SCAN,
	PORT_USE_TIEOFF
    };

    flags = 0;

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, pin_keys);

	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in PINS "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}
	switch (keyword)
	{
	    case DEF_PINS_START:		/* "-" keyword */
		hasports = FALSE;

		// Flag an error if a pin was waiting on a layer
		// specification that was never given.

		if (pending)
		{
		    LefError(DEF_ERROR, "Pin specified without layer, was not placed.\n");
		}

		/* Update the record of the number of pins		*/
		/* processed and spit out a message for every 5% done.	*/

		LefEstimate(processed++, total, "pins");

		/* Get pin name */
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%2047s", pinname) != 1)
		{
		    LefError(DEF_ERROR, "Bad pin statement:  Need pin name\n");
		    LefEndStatement(f);
		    break;
		}
		pending = FALSE;
		curlayer = -1;

		/* Now do a search through the line for "+" entries	*/
		/* And process each.					*/

		while ((token = LefNextToken(f, TRUE)) != NULL)
		{
		    if (*token == ';') break;
		    if (*token != '+') continue;

		    token = LefNextToken(f, TRUE);
		    subkey = LookupFull(token, pin_property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown pin property \"%s\" in "
				"PINS definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_PINS_PROP_SPECIAL:
			    /* Ignore this */
			    break;
			case DEF_PINS_PROP_PORT:
			    /* Ignore this, except that each port adds to   */
			    /* the count of total pins processed.  Note	    */
			    /* that since "processed" is incremented before */
			    /* the first PORT is seen, then "processed"	    */
			    /* should not be incremented until the 2nd PORT */
			    if (hasports) processed++;
			    hasports = TRUE;
			    break;
			case DEF_PINS_PROP_USE:
			    token = LefNextToken(f, TRUE);
			    subkey = LookupFull(token, pin_uses);
			    if (subkey < 0)
				LefError(DEF_ERROR, "Unknown pin use \"%s\"\n", token);
			    else
				pinUse = lef_use_to_bitmask[subkey];
			    break;
			case DEF_PINS_PROP_NET:
			    /* Get the net name, but ignore it */
			    token = LefNextToken(f, TRUE);
			    break;
			case DEF_PINS_PROP_DIR:
			    token = LefNextToken(f, TRUE);
			    subkey = LookupFull(token, pin_classes);
			    if (subkey < 0)
				LefError(DEF_ERROR, "Unknown pin class \"%s\"\n", token);
			    else
				pinDir = lef_class_to_bitmask[subkey];
			    break;
			case DEF_PINS_PROP_LAYER:
			    curlayer = LefReadLayer(f, FALSE);
			    currect = LefReadRect(f, curlayer, oscale);

			    newRect = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
			    newRect->r_type = curlayer;
			    newRect->r_r = *currect;
			    newRect->r_next = rectList;
			    rectList = newRect;

			    if (pending)
			    {
				/* If layer was unknown, set to space and force	*/
				/* non-sticky.					*/
				flags = PORT_DIR_MASK;
				if (curlayer < 0)
				    curlayer = TT_SPACE;
				else
				    flags |= LABEL_STICKY;

				free_magic1_t mm1 = freeMagic1_init();
				while (rectList != NULL)
				{
				    GeoTransRect(&t, &rectList->r_r, &topRect);
				    DBPaint(rootDef, &topRect, rectList->r_type);
				    // DBPutLabel(rootDef, &topRect, -1, pinname,
				    //		rectList->r_type,
				    //		pinDir | pinUse | flags, pinNum);
				    width = (topRect.r_xtop - topRect.r_xbot);
				    height = (topRect.r_ytop - topRect.r_ybot);
				    rot = 0;
				    if (height > (width * 2))
				    {
					int temp = height;
					height = width;
					width = temp;
					rot = 90;
				    }
				    size = DRCGetDefaultLayerWidth(rectList->r_type);
				    while ((size << 1) < height) size <<= 1;
				    size <<= 3;		/* Fonts are in 8x units */
				    DBPutFontLabel(rootDef, &topRect,
						0, size, rot, &GeoOrigin,
						GEO_CENTER, pinname,
				    		rectList->r_type,
				    		pinDir | pinUse | flags, pinNum);
				    freeMagic1(&mm1, rectList);
				    rectList = rectList->r_next;
				}
				freeMagic1_end(&mm1);
				pending = FALSE;
				pinNum++;
			    }
			    break;
			case DEF_PINS_PROP_FIXED:
			case DEF_PINS_PROP_COVER:
			case DEF_PINS_PROP_PLACED:
			    DefReadLocation(NULL, f, oscale, &t, FALSE);
			    if (curlayer == -1)
				pending = TRUE;
			    else
			    {
				/* If layer was unknown, set to space and force	*/
				/* non-sticky.					*/
				flags = PORT_DIR_MASK;
				if (curlayer < 0)
				    curlayer = TT_SPACE;
				else
				    flags |= LABEL_STICKY;

				free_magic1_t mm1 = freeMagic1_init();
				while (rectList != NULL)
				{
				    GeoTransRect(&t, &rectList->r_r, &topRect);
				    DBPaint(rootDef, &topRect, rectList->r_type);
				    // DBPutLabel(rootDef, &topRect, -1, pinname,
				    //		rectList->r_type,
				    //		pinDir | pinUse | flags, pinNum);
				    width = (topRect.r_xtop - topRect.r_xbot);
				    height = (topRect.r_ytop - topRect.r_ybot);
				    rot = 0;
				    if (height > (width * 2))
				    {
					int temp = height;
					height = width;
					width = temp;
					rot = 90;
				    }
				    size = DRCGetDefaultLayerWidth(rectList->r_type);
				    while ((size << 1) < height) size <<= 1;
				    size <<= 3;		/* Fonts are in 8x units */

				    /* If DEF file is being imported to annotate a
				     * layout, then remove any existing label in
				     * the layout that matches the PIN record.
				     */
				    if (annotate)
					DBEraseLabelsByContent(rootDef, &topRect,
								-1, pinname);

				    DBPutFontLabel(rootDef, &topRect,
						0, size, rot, &GeoOrigin,
						GEO_CENTER, pinname,
				    		rectList->r_type,
				    		pinDir | pinUse | flags, pinNum);
				    freeMagic1(&mm1, rectList);
				    rectList = rectList->r_next;
				}
				freeMagic1_end(&mm1);
				pending = FALSE;
				pinNum++;
			    }
			    break;
		    }
		}

		break;

	    case DEF_PINS_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Pins END statement missing.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_PINS_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d pins total.\n", processed);
    else
	LefError(DEF_WARNING, "Number of pins read (%d) does not match "
		"the number declared (%d).\n", processed, total);
}

/*
 *------------------------------------------------------------
 *
 * DefReadBlockages --
 *
 *	Read a BLOCKAGES section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Generates layout
 *
 *------------------------------------------------------------
 */

enum def_block_keys {DEF_BLOCK_START = 0, DEF_BLOCK_END};
enum def_block_prop_keys {
	DEF_BLOCK_PROP_RECT = 0, DEF_BLOCK_PROP_LAYER};

void
DefReadBlockages(
    FILE *f,
    CellDef *rootDef,
    const char *sname,
    float oscale,
    int total)
{
    const char *token;
    int keyword, subkey;
    int processed = 0;
    TileType curlayer;
    Rect *currect;

    static const char * const block_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const block_property_keys[] = {
	"RECT",
	"LAYER",
	NULL
    };

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, block_keys);

	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in BLOCKAGES "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}
	switch (keyword)
	{
	    case DEF_BLOCK_START:		/* "-" keyword */

		/* Update the record of the number of blockages		*/
		/* processed and spit out a message for every 5% done.	*/

		LefEstimate(processed++, total, "blockages");

		while ((token = LefNextToken(f, TRUE)) != NULL)
		{
		    if (*token == ';')
			break;

		    subkey = LookupFull(token, block_property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown blockage property \"%s\" in "
				"BLOCKAGES definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_BLOCK_PROP_LAYER:
			    curlayer = LefReadLayer(f, TRUE);
			    break;

			case DEF_BLOCK_PROP_RECT:
			    currect = LefReadRect(f, curlayer, oscale);
			    DBPaint(rootDef, currect, curlayer);
			    break;
		    }
		}
		break;

	    case DEF_BLOCK_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Blockage END statement missing.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_BLOCK_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d blockage%s.\n", processed,
		((processed > 1) ? "s" : ""));
    else
	LefError(DEF_WARNING, "Number of blockages read (%d) does not match "
		"the number declared (%d).\n", processed, total);
}

/*
 *------------------------------------------------------------
 *
 * DefReadVias --
 *
 *	Read a VIAS section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Technically, this routine should be creating a cell for
 *	each defined via.  For now, it just computes the bounding
 *	rectangle and layer.
 *
 *------------------------------------------------------------
 */

enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END};
enum def_vias_prop_keys {
	DEF_VIAS_PROP_RECT = 0, DEF_VIAS_PROP_VIARULE,
	DEF_VIAS_PROP_CUTSIZE, DEF_VIAS_PROP_LAYERS,
	DEF_VIAS_PROP_CUTSPACING, DEF_VIAS_PROP_ENCLOSURE,
	DEF_VIAS_PROP_ROWCOL};

void
DefReadVias(
    FILE *f,
    const char *sname,
    float oscale,
    int total)
{
    const char *token;
    char vianame[LEF_LINE_MAX];
    int keyword, subkey;
    int processed = 0;
    TileType curlayer;
    lefLayer *lefl;
    HashEntry *he;

    /* For generated vias */
    bool generated = FALSE;
    int sizex, sizey, spacex, spacey;
    int encbx, encby, enctx, encty;
    int rows = 1, cols = 1;
    TileType tlayer, clayer, blayer;

    static const char * const via_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const via_property_keys[] = {
	"RECT",
	"VIARULE",
	"CUTSIZE",
	"LAYERS",
	"CUTSPACING",
	"ENCLOSURE",
	"ROWCOL",
	NULL
    };

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, via_keys);

	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in VIAS "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}
	switch (keyword)
	{
	    case DEF_VIAS_START:		/* "-" keyword */

		/* Update the record of the number of vias		*/
		/* processed and spit out a message for every 5% done.	*/

		LefEstimate(processed++, total, "vias");

		/* If not otherwise specified, rows and columns default to 1 */
		rows = cols = 1;

		/* Get via name */
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%2047s", vianame) != 1)
		{
		    LefError(DEF_ERROR, "Bad via statement:  Need via name\n");
		    LefEndStatement(f);
		    break;
		}
		he = HashFind(&LefInfo, vianame);
		lefl = (lefLayer *)HashGetValue(he);
		if (lefl == NULL)
		{
		    lefl = (lefLayer *)mallocMagic(sizeof(lefLayer));
		    lefl->type = -1;
		    lefl->obsType = -1;
		    lefl->lefClass = CLASS_VIA;
		    lefl->info.via.area = GeoNullRect;
		    lefl->info.via.cell = (CellDef *)NULL;
		    lefl->info.via.lr = (LinkedRect *)NULL;
		    HashSetValue(he, lefl);
		    lefl->canonName = (const char *)he->h_key.h_name;
		}
		else
		{
		    LefError(DEF_WARNING, "Composite via \"%s\" redefined.\n", vianame);
		    lefl = LefRedefined(lefl, vianame);
		}

		/* Now do a search through the line for "+" entries	*/
		/* And process each.					*/

		while ((token = LefNextToken(f, TRUE)) != NULL)
		{
		    if (*token == ';') {
			if (generated == TRUE) {
			    /* Complete the generated via */
			    LefGenViaGeometry(f, lefl,
				    sizex, sizey, spacex, spacey,
				    encbx, encby, enctx, encty,
				    rows, cols, tlayer, clayer, blayer,
				    oscale);
			}
			break;
		    }
		    if (*token != '+') continue;

		    token = LefNextToken(f, TRUE);
		    subkey = LookupFull(token, via_property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown via property \"%s\" in "
				"VIAS definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_VIAS_PROP_RECT:
			    curlayer = LefReadLayer(f, FALSE);
			    LefAddViaGeometry(f, lefl, curlayer, oscale);
			    break;

			case DEF_VIAS_PROP_VIARULE:
			    token = LefNextToken(f, TRUE);
			    /* Ignore this.  To do:  Parse VIARULE statements	*/
			    /* and use the rule to fill any missing values.	*/
			    break;
			case DEF_VIAS_PROP_CUTSIZE:
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &sizex) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
				/* To do:  Get cut size from DRC ruleset */
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &sizey) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
				/* To do:  Get cut size from DRC ruleset */
			    }
			    generated = TRUE;
			    break;
			case DEF_VIAS_PROP_LAYERS:
			    blayer = LefReadLayer(f, FALSE);
			    clayer = LefReadLayer(f, FALSE);
			    tlayer = LefReadLayer(f, FALSE);

			    /* Provisional behavior:  A known tool generating	*/
			    /* DEF uses the order (bottom, top, cut).  This may	*/
			    /* be a bug in the tool and an issue is being	*/
			    /* raised.  However, there is no harm in detecting	*/
			    /* which layer is the cut and swapping as needed.	*/

			    if (!DBIsContact(clayer))
			    {
				TileType swaplayer;
				LefError(DEF_WARNING, "Improper layer order for"
					" VIARULE.\n");
				if (DBIsContact(tlayer))
				{
				    swaplayer = clayer;
				    clayer = tlayer;
				    tlayer = swaplayer;
				}
				else if (DBIsContact(blayer))
				{
				    swaplayer = clayer;
				    clayer = blayer;
				    blayer = swaplayer;
				}
				else
				    LefError(DEF_ERROR, "No cut layer specified in"
					    " VIARULE.\n");
			    }

			    generated = TRUE;
			    break;
			case DEF_VIAS_PROP_CUTSPACING:
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &spacex) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
				/* To do:  Get cut spacing from DRC ruleset */
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &spacey) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
				/* To do:  Get cut spacing from DRC ruleset */
			    }
			    generated = TRUE;
			    break;
			case DEF_VIAS_PROP_ENCLOSURE:
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &encbx) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
				/* To do:  Get cut enclosures from DRC ruleset */
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &encby) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
				/* To do:  Get cut enclosures from DRC ruleset */
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &enctx) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
				/* To do:  Get cut enclosures from DRC ruleset */
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &encty) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
				/* To do:  Get cut enclosures from DRC ruleset */
			    }
			    generated = TRUE;
			    break;
			case DEF_VIAS_PROP_ROWCOL:
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &rows) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
				rows = 1;
			    }
			    token = LefNextToken(f, TRUE);
			    if (sscanf(token, "%d", &cols) != 1)
			    {
				LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
				cols = 1;
			    }
			    generated = TRUE;
			    break;
		    }
		}
		break;

	    case DEF_VIAS_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Vias END statement missing.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_VIAS_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d vias total.\n", processed);
    else
	LefError(DEF_WARNING, "Number of vias read (%d) does not match "
		"the number declared (%d).\n", processed, total);
}

/*
 *------------------------------------------------------------
 *
 * DefReadComponents --
 *
 *	Read a COMPONENTS section from a DEF file.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Many.  Cell definitions and uses are created and added to
 *	the database.
 *
 *------------------------------------------------------------
 */

enum def_comp_keys {DEF_COMP_START = 0, DEF_COMP_END};
enum def_prop_keys {
	DEF_PROP_FIXED = 0, DEF_PROP_COVER,
	DEF_PROP_PLACED, DEF_PROP_UNPLACED,
	DEF_PROP_SOURCE, DEF_PROP_WEIGHT, DEF_PROP_FOREIGN,
	DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY,
	DEF_PROP_EEQMASTER};

void
DefReadComponents(
    FILE *f,
    CellDef *rootDef,
    const char *sname,
    float oscale,
    int total)
{
    CellDef *defMacro;
    CellUse *defUse;
    Transform t;
    const char *token;
    char *dptr;
    char *usename, usename_buf[512];
    int usename_len;
    int keyword, subkey;
    int processed = 0;

    static const char * const component_keys[] = {
	"-",
	"END",
	NULL
    };

    static const char * const property_keys[] = {
	"FIXED",
	"COVER",
	"PLACED",
	"UNPLACED",
	"SOURCE",
	"WEIGHT",
	"FOREIGN",
	"REGION",
	"GENERATE",
	"PROPERTY",
	"EEQMASTER",
	NULL
    };

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, component_keys);

	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in COMPONENT "
			"definition; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}
	switch (keyword)
	{
	    case DEF_COMP_START:		/* "-" keyword */

		/* Update the record of the number of components	*/
		/* processed and spit out a message for every 5% done.	*/

		LefEstimate(processed++, total, "subcell instances");

		/* Get use and macro names */
		token = LefNextToken(f, TRUE);

		usename_len = strlen(token);
		if (!usename_len)
		{
		    LefError(DEF_ERROR, "Bad component statement:  Need "
			    "use and macro names\n");
		    LefEndStatement(f);
		    break;
		}

		/* Use stack buffer if we can , else go for the heap */
		if (strlen(token) < sizeof(usename_buf))
		{
			strcpy(usename_buf, token);
			usename = usename_buf;
		}
		else
		{
			usename = StrDup(NULL, token);
		}

		/* Magic prohibits slashes and commas in use names	*/
		/* when using the "identify" command.  Removing these	*/
		/* restrictions (at least the slash) is quite complex,	*/
		/* but really should be taken care of, since no other	*/
		/* tools consider this an illegal use, that I'm aware	*/
		/* of.							*/

		for (dptr = usename; *dptr; dptr++)
		    if ((*dptr == '/') || (*dptr == ','))
		    {
			LefError(DEF_WARNING, "Character in instance name "
				"converted to underscore.\n");
			*dptr = '_';
		    }

		token = LefNextToken(f, TRUE);

		/* Find the corresponding macro definition */
		defUse = NULL;
		defMacro = DBCellLookDef(token);

		if (defMacro == (CellDef *)NULL)
		{
		    /* Before giving up, assume that this cell has a	*/
		    /* magic .mag layout file.				*/
		    defMacro = DBCellNewDef(token);
		    defMacro->cd_flags &= ~CDNOTFOUND;

		    if (!DBCellRead(defMacro, TRUE, TRUE, NULL))
		    {
		        LefError(DEF_ERROR, "Cell %s is not defined.  Maybe you "
				"have not read the corresponding LEF file?\n",
				token);
		        LefEndStatement(f);
			DBCellDeleteDef(defMacro);
			defMacro = NULL;
		    }
		    else
		       DBReComputeBbox(defMacro);
		}

		/* Create a use for this celldef in the edit cell */
		/* Don't process properties for cells we could not find */
		if (defMacro == NULL)
		    break;

		defUse = DBCellNewUse(defMacro, usename);

		if (usename != usename_buf)
		    freeMagic(usename);
		usename = NULL;

		if (defUse == NULL)
		{
		    LefEndStatement(f);
		    break;
		}
		DBLinkCell(defUse, rootDef);

		/* Now do a search through the line for "+" entries	*/
		/* And process each.					*/

		while ((token = LefNextToken(f, TRUE)) != NULL)
		{
		    if (*token == ';') break;
		    if (*token != '+') continue;

		    token = LefNextToken(f, TRUE);
		    subkey = LookupFull(token, property_keys);
		    if (subkey < 0)
		    {
			LefError(DEF_INFO, "Unknown component property \"%s\" in "
				"COMPONENT definition; ignoring.\n", token);
			continue;
		    }
		    switch (subkey)
		    {
			case DEF_PROP_PLACED:
			case DEF_PROP_FIXED:
			case DEF_PROP_COVER:
			    DefReadLocation(defUse, f, oscale, &t, FALSE);
			    break;
			case DEF_PROP_UNPLACED:
			    DefReadLocation(defUse, f, oscale, &t, TRUE);
			    break;
			case DEF_PROP_SOURCE:
			case DEF_PROP_WEIGHT:
			case DEF_PROP_FOREIGN:
			case DEF_PROP_REGION:
			case DEF_PROP_GENERATE:
			case DEF_PROP_PROPERTY:
			case DEF_PROP_EEQMASTER:
			    token = LefNextToken(f, TRUE);
			    break;
		    }
		}

		/* Place the cell */
		if (defUse != NULL)
		{
		    DBPlaceCell(defUse, rootDef);
		    defUse = NULL;
		}
		break;

	    case DEF_COMP_END:
		if (!LefParseEndStatement(f, sname))
		{
		    LefError(DEF_ERROR, "Component END statement missing.\n");
		    keyword = -1;
		}

		/* Finish final call by placing the cell use */
		if ((total > 0) && (defUse != NULL))
		{
		    DBPlaceCell(defUse, rootDef);
		    defUse = NULL;
		}
		break;
	}
	if (keyword == DEF_COMP_END) break;
    }

    if (processed == total)
	TxPrintf("  Processed %d subcell instances total.\n", processed);
    else
	LefError(DEF_WARNING, "Number of subcells read (%d) does not match "
		"the number declared (%d).\n", processed, total);
}

/*
 *------------------------------------------------------------
 * DefNewCell --
 *
 *	Create a new CellDef for the DEF file contents.
 *
 * Returns:
 *	Pointer to new CellDef
 *
 * Side effects:
 *	If a cell of the given name did not exist, then
 *	a new CellDef is allocated.
 *------------------------------------------------------------
 */
CellDef *
DefNewCell(
    const char *name)
{
    CellDef *newDef;

    newDef = DBCellLookDef(name);
    if (newDef == NULL)	
    {
	newDef = DBCellNewDef(name);
	DBReComputeBbox(newDef);
 	DBCellClearDef(newDef);
	DBCellSetAvail(newDef);
    }
    return newDef;
}

/*
 *------------------------------------------------------------
 *
 * DefRead --
 *
 *	Read a .def file into a magic layout.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Many.  Cell definitions and uses are created and added to
 *	the database.
 *
 *------------------------------------------------------------
 */

/* Enumeration of sections defined in DEF files */

enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
	DEF_UNITS, DEF_DESIGN, DEF_REGIONS, DEF_ROW, DEF_TRACKS,
	DEF_GCELLGRID, DEF_DIVIDERCHAR, DEF_BUSBITCHARS,
	DEF_PROPERTYDEFINITIONS, DEF_DEFAULTCAP, DEF_TECHNOLOGY,
	DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS,
	DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS,
	DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS,
	DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION, DEF_BLOCKAGES,
	DEF_NONDEFAULTRULES, DEF_END};

CellDef *
DefRead(
    const char *inName,
    bool dolabels,
    bool annotate,
    bool noblockage)
{
    CellDef *rootDef;
    FILE *f;
    char *filename;
    const char *token;
    PropertyRecord *proprec;
    int keyword, dscale, total;
    float oscale;
    Rect *dierect;
    bool design_is_root = FALSE;

    static const char * const sections[] = {
	"VERSION",
	"NAMESCASESENSITIVE",
	"UNITS",
	"DESIGN",
	"REGIONS",
	"ROW",
	"TRACKS",
	"GCELLGRID",
	"DIVIDERCHAR",
	"BUSBITCHARS",
	"PROPERTYDEFINITIONS",
	"DEFAULTCAP",
	"TECHNOLOGY",
	"HISTORY",
	"DIEAREA",
	"COMPONENTS",
	"VIAS",
	"PINS",
	"PINPROPERTIES",
	"SPECIALNETS",
	"NETS",
	"IOTIMINGS",
	"SCANCHAINS",
	"CONSTRAINTS",
	"GROUPS",
	"BEGINEXT",
	"BLOCKAGES",
	"NONDEFAULTRULES",
	"END",
	NULL
    };

#ifdef MAGIC_WRAPPER
#ifndef MAGIC_NO_TK
    Tk_RestrictProc *oldProc;
    ClientData oldArg;
#endif /* MAGIC_NO_TK */
#endif /* MAGIC_WRAPPER */

    /* "annotate" implies "dolabels" whether set or not */
    if (annotate) dolabels = TRUE;

    /* Make sure we have a valid LefInfo hash table, even if it's empty */
    if (LefInfo.ht_table == (HashEntry **) NULL)
	LefTechInit();

    f = lefFileOpen(NULL, inName, ".def", "r", &filename);

    if (f == NULL)
    {
#ifdef MAGIC_WRAPPER
	TxError("Cannot open input file %s (%s).\n", filename,
		strerror(errno));
#else
	TxError("Cannot open input file: ");
	perror(filename);
#endif
	return NULL;
    }

#ifdef MAGIC_WRAPPER
#ifndef MAGIC_NO_TK
    /* This routine may be long-running and events to refresh the
     * console will be periodically run to allow the progress status
     * to be displayed.  Force a restriction on event processing to
     * exclude key and button events so that it is not possible to
     * corrupt the database during DEF reads.
     */

    if (SigInterruptOnSigIO != -1)	/* Check for batch mode */
	oldProc = Tk_RestrictEvents(RestrictInputProc, (ClientData)NULL, &oldArg);
#endif /* MAGIC_NO_TK */
#endif /* MAGIC_WRAPPER */

    /* Initialize */

    TxPrintf("Reading DEF data from file %s.\n", filename);
    TxPrintf("This action cannot be undone.\n");
    UndoDisable();

    rootDef = NULL;

    oscale = CIFGetOutputScale(1000);
    lefCurrentLine = 0;

    /* Read file contents */

    while ((token = LefNextToken(f, TRUE)) != NULL)
    {
	keyword = LookupFull(token, sections);
	if (keyword < 0)
	{
	    LefError(DEF_INFO, "Unknown keyword \"%s\" in DEF file; ignoring.\n", token);
	    LefEndStatement(f);
	    continue;
	}
	switch (keyword)
	{
	    case DEF_VERSION:
		LefEndStatement(f);
		break;
	    case DEF_NAMESCASESENSITIVE:
		LefEndStatement(f);
		break;
	    case DEF_TECHNOLOGY:
		token = LefNextToken(f, TRUE);
		if (strcmp(token, DBTechName))
		{
		    LefError(DEF_WARNING, "DEF technology name \"%s\" does not"
			" match current magic technology name \"%s\"\n",
			token, DBTechName);
		}
		LefEndStatement(f);
	 	break;
	    case DEF_REGIONS:
		LefSkipSection(f, sections[DEF_REGIONS]);
		break;
	    case DEF_DESIGN:
		token = LefNextToken(f, TRUE);
		
		/* If rootDef is not NULL, then it was created before DESIGN
		 * was specified;  this should not happen, but if so, then
		 * rename the rootDef rather than creating a new CellDef.
		 */
		if (rootDef == NULL)	
		    rootDef = DefNewCell(token);
		else
		    DBCellRenameDef(rootDef, token);

		LefEndStatement(f);
		break;
	    case DEF_UNITS:
		token = LefNextToken(f, TRUE);
		token = LefNextToken(f, TRUE);
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &dscale) != 1)
		{
		    LefError(DEF_ERROR, "Invalid syntax for UNITS statement.\n");
		    LefError(DEF_INFO, "Assuming default value of 100\n");
		    dscale = 100;
		}
		/* We don't care if the scale is 100, 200, 1000, or 2000. */
		/* Do we need to deal with numeric roundoff issues?	  */
		oscale *= (float)dscale;
		LefEndStatement(f);
		break;
	    case DEF_ROW:
		LefEndStatement(f);
		break;
	    case DEF_TRACKS:
		LefEndStatement(f);
		break;
	    case DEF_GCELLGRID:
		LefEndStatement(f);
		break;
	    case DEF_DIVIDERCHAR:
		LefEndStatement(f);
		break;
	    case DEF_BUSBITCHARS:
		LefEndStatement(f);
		break;
	    case DEF_HISTORY:
		LefEndStatement(f);
		break;
	    case DEF_DIEAREA:
		dierect = LefReadRect(f, 0, oscale);
		proprec = (PropertyRecord *)mallocMagic(intPropertyRecordSize(4));
		proprec->prop_type = PROPERTY_TYPE_DIMENSION;
		proprec->prop_len = 4;
		proprec->prop_value.prop_integer[0] = dierect->r_xbot;
		proprec->prop_value.prop_integer[1] = dierect->r_ybot;
		proprec->prop_value.prop_integer[2] = dierect->r_xtop;
		proprec->prop_value.prop_integer[3] = dierect->r_ytop;
		if (rootDef == NULL) rootDef = DefNewCell(inName);
		DBPropPut(rootDef, "FIXED_BBOX", proprec);

		LefEndStatement(f);
		break;
	    case DEF_PROPERTYDEFINITIONS:
		LefSkipSection(f, sections[DEF_PROPERTYDEFINITIONS]);
		break;
	    case DEF_DEFAULTCAP:
		LefSkipSection(f, sections[DEF_DEFAULTCAP]);
		break;
	    case DEF_COMPONENTS:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (annotate)
		    LefSkipSection(f, sections[DEF_COMPONENTS]);
		else
		{
		    if (rootDef == NULL) rootDef = DefNewCell(inName);
		    DefReadComponents(f, rootDef, sections[DEF_COMPONENTS],
				oscale, total);
		}
		break;
	    case DEF_VIAS:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		DefReadVias(f, sections[DEF_VIAS], oscale, total);
		break;
	    case DEF_PINS:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (rootDef == NULL) rootDef = DefNewCell(inName);
		DefReadPins(f, rootDef, sections[DEF_PINS], oscale, total, annotate);
		break;
	    case DEF_PINPROPERTIES:
		LefSkipSection(f, sections[DEF_PINPROPERTIES]);
		break;
	    case DEF_SPECIALNETS:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (rootDef == NULL) rootDef = DefNewCell(inName);
		DefReadNets(f, rootDef, sections[DEF_SPECIALNETS], oscale, TRUE,
			dolabels, annotate, total);
		break;
	    case DEF_NETS:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (rootDef == NULL) rootDef = DefNewCell(inName);
		DefReadNets(f, rootDef, sections[DEF_NETS], oscale, FALSE,
			dolabels, annotate, total);
		break;
	    case DEF_NONDEFAULTRULES:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (rootDef == NULL) rootDef = DefNewCell(inName);
		DefReadNonDefaultRules(f, rootDef, sections[DEF_NONDEFAULTRULES],
			oscale, total);
		break;
	    case DEF_IOTIMINGS:
		LefSkipSection(f, sections[DEF_IOTIMINGS]);
		break;
	    case DEF_SCANCHAINS:
		LefSkipSection(f, sections[DEF_SCANCHAINS]);
		break;
	    case DEF_CONSTRAINTS:
		LefSkipSection(f, sections[DEF_CONSTRAINTS]);
		break;
	    case DEF_GROUPS:
		LefSkipSection(f, sections[DEF_GROUPS]);
		break;
	    case DEF_EXTENSION:
		LefSkipSection(f, sections[DEF_EXTENSION]);
		break;
	    case DEF_BLOCKAGES:
		token = LefNextToken(f, TRUE);
		if (sscanf(token, "%d", &total) != 1) total = 0;
		LefEndStatement(f);
		if (annotate || noblockage)
		    LefSkipSection(f, sections[DEF_BLOCKAGES]);
		else
		{
		    if (rootDef == NULL) rootDef = DefNewCell(inName);
		    DefReadBlockages(f, rootDef, sections[DEF_BLOCKAGES],
				oscale, total);
		}
		break;
	    case DEF_END:
		if (!LefParseEndStatement(f, "DESIGN"))
		{
		    LefError(DEF_ERROR, "END statement out of context.\n");
		    keyword = -1;
		}
		break;
	}
	if (keyword == DEF_END) break;
    }
    TxPrintf("DEF read: Processed %d lines.\n", lefCurrentLine);
    LefError(DEF_SUMMARY, NULL);    /* print statement of errors, if any, and reset */

    /* Cleanup */

    if (rootDef != NULL) 
    {
	DBAdjustLabels(rootDef, &TiPlaneRect);
	DBReComputeBbox(rootDef);
	DBWAreaChanged(rootDef, &rootDef->cd_bbox, DBW_ALLWINDOWS,
		&DBAllButSpaceBits);
	DBCellSetModified(rootDef, TRUE);
    }
    else
	TxPrintf("DEF read: Design has no contents.\n");

    if (f != NULL) fclose(f);
    UndoEnable();

#ifdef MAGIC_WRAPPER
#ifndef MAGIC_NO_TK
    /* Restore full event access */
    if (SigInterruptOnSigIO != -1)	/* Check for batch mode */
	Tk_RestrictEvents(oldProc, oldArg, &oldArg);
#endif /* MAGIC_NO_TK */
#endif /* MAGIC_WRAPPER */

    return rootDef;
}
