2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* CIFwrite.c --
|
|
|
|
|
*
|
|
|
|
|
* Output of CIF.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFwrite.c,v 1.2 2010/06/24 12:37:15 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "database/databaseInt.h"
|
|
|
|
|
#include "utils/tech.h"
|
|
|
|
|
#include "utils/stack.h"
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
|
|
|
|
|
/* Forward declarations */
|
2024-10-04 12:26:58 +02:00
|
|
|
extern int cifWriteInitFunc(CellDef *def);
|
|
|
|
|
extern int cifWriteMarkFunc(CellUse *use);
|
|
|
|
|
extern int cifWritePaintFunc(Tile *tile, FILE *f);
|
|
|
|
|
extern int cifWriteLabelFunc(Tile *tile, FILE *f);
|
|
|
|
|
extern int cifWriteUseFunc(CellUse *use, FILE *f);
|
|
|
|
|
extern void cifOutPreamble(FILE *outf, CellDef *cell);
|
|
|
|
|
extern void cifOut(FILE *outf);
|
|
|
|
|
extern void cifOutFunc(CellDef *def, FILE *f);
|
|
|
|
|
extern void GrClipTriangle(Rect *r, Rect *c, int clipped, TileType dinfo, Point *points, int *np);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Current cell number in CIF numbering scheme */
|
|
|
|
|
|
|
|
|
|
static int cifCellNum;
|
|
|
|
|
|
|
|
|
|
/* Stack of definitions left to process for generating CIF */
|
|
|
|
|
|
|
|
|
|
Stack *cifStack;
|
|
|
|
|
|
|
|
|
|
/* Scale factor for outputting paint: */
|
|
|
|
|
|
|
|
|
|
int cifPaintScale;
|
|
|
|
|
|
|
|
|
|
/* Current layer name. If non-NULL, then cifWritePaintFunc outputs
|
|
|
|
|
* this string to the file before outputting a rectangle, then nulls.
|
|
|
|
|
* This way, the layer name only gets output when there's actually
|
|
|
|
|
* stuff on that layer.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *cifPaintLayerName;
|
|
|
|
|
|
|
|
|
|
/* TRUE if area labels should be output */
|
|
|
|
|
bool CIFDoAreaLabels = FALSE;
|
|
|
|
|
|
|
|
|
|
/* TRUE if cell ids should be output */
|
|
|
|
|
bool CIFDoCellIdLabels = TRUE;
|
|
|
|
|
|
|
|
|
|
/* prefix string for pathnames */
|
|
|
|
|
char *CIFPathPrefix = NULL;
|
|
|
|
|
|
|
|
|
|
/* These are normally FALSE---enable at your own risk! */
|
|
|
|
|
bool CIFHierWriteDisable = FALSE;
|
|
|
|
|
bool CIFArrayWriteDisable = FALSE;
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFWrite --
|
|
|
|
|
*
|
|
|
|
|
* Write out the entire tree rooted at the supplied CellDef in CIF format,
|
|
|
|
|
* to the specified file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the cell could be written successfully, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes a file to disk.
|
|
|
|
|
* In the event of an error while writing out the cell,
|
|
|
|
|
* the external integer errno is set to the UNIX error
|
|
|
|
|
* encountered.
|
|
|
|
|
*
|
|
|
|
|
* Algorithm:
|
|
|
|
|
* We make a depth-first traversal of the entire design tree,
|
|
|
|
|
* marking each cell with a CIF symbol number and then outputting
|
|
|
|
|
* it to the CIF file. If a given cell is not read in when we
|
|
|
|
|
* visit it, we read it in.
|
|
|
|
|
*
|
|
|
|
|
* No hierarchical design rule checking or bounding box computation
|
|
|
|
|
* occur during this traversal -- both are explicitly avoided.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFWrite(
|
|
|
|
|
CellDef *rootDef, /* Pointer to CellDef to be written */
|
|
|
|
|
FILE *f) /* Open output file */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
bool good;
|
|
|
|
|
int oldCount = DBWFeedbackCount;
|
2024-04-29 23:43:37 +02:00
|
|
|
CellDef *err_def;
|
2017-04-25 14:41:48 +02:00
|
|
|
CellUse dummy;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure that the entire hierarchy rooted at rootDef is
|
|
|
|
|
* read into memory and that timestamp mismatches are resolved
|
|
|
|
|
* (this is needed so that we know that bounding boxes are OK).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
dummy.cu_def = rootDef;
|
2024-04-29 23:43:37 +02:00
|
|
|
err_def = DBCellReadArea(&dummy, &rootDef->cd_bbox, TRUE);
|
|
|
|
|
if (err_def != NULL)
|
2021-01-14 21:21:39 +01:00
|
|
|
{
|
|
|
|
|
TxError("Failure to read in entire subtree of the cell.\n");
|
2024-04-29 23:43:37 +02:00
|
|
|
TxError("Failed on cell %s.\n", err_def->cd_name);
|
2021-01-14 21:21:39 +01:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
DBFixMismatch();
|
|
|
|
|
|
|
|
|
|
if (CIFCurStyle->cs_reducer == 0)
|
|
|
|
|
{
|
|
|
|
|
TxError("The current CIF output style can only be used for writing\n");
|
|
|
|
|
TxError("Calma output. Try picking another output style.\n");
|
2021-01-14 21:21:39 +01:00
|
|
|
return (FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Go through all cells currently having CellDefs in the
|
|
|
|
|
* def symbol table and mark them with negative symbol numbers.
|
|
|
|
|
*/
|
|
|
|
|
(void) DBCellSrDefs(0, cifWriteInitFunc, (ClientData) NULL);
|
|
|
|
|
cifCellNum = (-2);
|
|
|
|
|
rootDef->cd_client = (ClientData) -1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Start by pushing the root def on the stack of cell defs
|
|
|
|
|
* to be processed.
|
|
|
|
|
*/
|
|
|
|
|
cifStack = StackNew(100);
|
|
|
|
|
StackPush((ClientData) rootDef, cifStack);
|
|
|
|
|
cifOutPreamble(f, rootDef);
|
|
|
|
|
cifOut(f);
|
|
|
|
|
StackFree(cifStack);
|
|
|
|
|
if ((int) rootDef->cd_client < 0)
|
|
|
|
|
rootDef->cd_client = (ClientData) (- (int) rootDef->cd_client);
|
|
|
|
|
|
|
|
|
|
/* See if any problems occurred. */
|
|
|
|
|
|
|
|
|
|
if (DBWFeedbackCount != oldCount)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("%d problems occurred. See feedback entries.\n",
|
|
|
|
|
DBWFeedbackCount - oldCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we are almost done.
|
|
|
|
|
* Just output a call on the root cell
|
|
|
|
|
*/
|
|
|
|
|
fprintf(f, "C %d;\nEnd\n", (int) rootDef->cd_client);
|
|
|
|
|
good = !ferror(f);
|
|
|
|
|
return (good);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifWriteInitFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function called on behalf of CIFWrite() above.
|
|
|
|
|
* Responsible for setting the cif number of each cell to zero.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 to indicate that the search should continue.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modify the cif numbers of the cells they are passed.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifWriteInitFunc(
|
|
|
|
|
CellDef *def)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
def->cd_client = (ClientData) 0;
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifWriteMarkFunc --
|
|
|
|
|
*
|
|
|
|
|
* Called to add each cell def in the subcell plane of a parent
|
|
|
|
|
* to the stack of cells to be processed.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0 to indicate that DBCellEnum() should continue.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Pushes the cell def on the stack.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifWriteMarkFunc(
|
|
|
|
|
CellUse *use)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
if (use->cu_def->cd_client != (ClientData) 0) return 0;
|
|
|
|
|
use->cu_def->cd_client = (ClientData) cifCellNum;
|
|
|
|
|
cifCellNum -= 1;
|
|
|
|
|
StackPush((ClientData) use->cu_def, cifStack);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifOutPreamble --
|
|
|
|
|
*
|
|
|
|
|
* Write preamble in front of a CIF file for version control.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Preamble in CIF comment style - () are send to output file.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifOutPreamble(
|
|
|
|
|
FILE *outf,
|
|
|
|
|
CellDef *cell)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
extern char *MagicVersion;
|
|
|
|
|
extern char *MagicCompileTime;
|
|
|
|
|
char *now, *t;
|
|
|
|
|
struct tm *clock;
|
|
|
|
|
time_t t_stamp = time((time_t *) NULL);
|
|
|
|
|
|
|
|
|
|
clock = localtime(&t_stamp);
|
|
|
|
|
now = ctime(&t_stamp);
|
|
|
|
|
/* remove the '\n' at the end of the string... */
|
|
|
|
|
now[strlen(now)-1] = '\0';
|
|
|
|
|
|
|
|
|
|
fprintf(outf,"( @@user : %s );\n", (t = getenv("USER")) ? t : "?");
|
|
|
|
|
fprintf(outf,"( @@machine : %s );\n", (t = getenv("HOSTNAME")) ? t : "?");
|
|
|
|
|
fprintf(outf,"( @@source : %s );\n",(cell->cd_file) ? cell->cd_file : "?");
|
|
|
|
|
fprintf(outf,"( @@tool : Magic %s.%s );\n", MagicVersion, MagicRevision);
|
|
|
|
|
fprintf(outf,"( @@compiled : %s );\n", MagicCompileTime);
|
|
|
|
|
fprintf(outf,"( @@technology : %s );\n", DBTechName);
|
|
|
|
|
if (DBTechVersion)
|
|
|
|
|
fprintf(outf,"( @@version : %s );\n", DBTechVersion);
|
|
|
|
|
else
|
|
|
|
|
fprintf(outf,"( @@version : unknown );\n");
|
|
|
|
|
if (DBTechDescription)
|
|
|
|
|
fprintf(outf,"( @@techdesc : %s );\n", DBTechDescription);
|
|
|
|
|
fprintf(outf,"( @@style : %s );\n", CIFCurStyle->cs_name);
|
|
|
|
|
fprintf(outf,"( @@date : %s );\n", now);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifOut --
|
|
|
|
|
*
|
|
|
|
|
* Main loop of CIF generation. Pull a cell def from the stack
|
|
|
|
|
* and process it.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Causes CIF to be output.
|
|
|
|
|
* Returns when the stack is empty.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifOut(
|
|
|
|
|
FILE *outf)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CellDef *def;
|
2023-03-07 17:16:49 +01:00
|
|
|
bool needHier;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
while (!StackEmpty(cifStack))
|
|
|
|
|
{
|
|
|
|
|
def = (CellDef *) StackPop(cifStack);
|
|
|
|
|
if ((int) def->cd_client >= 0) continue; /* Already output */
|
|
|
|
|
if (SigInterruptPending) continue;
|
|
|
|
|
|
|
|
|
|
def->cd_client = (ClientData) (- (int) def->cd_client);
|
|
|
|
|
|
|
|
|
|
/* Read the cell in if it is not already available. */
|
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
2023-04-18 17:01:58 +02:00
|
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
|
|
|
continue;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Add any subcells to the stack. This must be done before
|
|
|
|
|
* outputting CIF to make sure that the subcells all have
|
|
|
|
|
* CIF numbers.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
(void) DBCellEnum(def, cifWriteMarkFunc, (ClientData) 0);
|
|
|
|
|
|
|
|
|
|
/* Output CIF for this cell */
|
|
|
|
|
|
|
|
|
|
cifOutFunc(def, outf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifOutFunc --
|
|
|
|
|
*
|
|
|
|
|
* Write out the definition for a single cell as CIF.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Appends to the open CIF output file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifOutFunc(
|
|
|
|
|
CellDef *def, /* Pointer to cell def to be written */
|
|
|
|
|
FILE *f) /* Open output file */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
Rect bigArea;
|
|
|
|
|
Label *lab;
|
|
|
|
|
int type;
|
|
|
|
|
CIFLayer *layer;
|
|
|
|
|
|
|
|
|
|
fprintf(f, "DS %d %d %d;\n", (int) def->cd_client,
|
|
|
|
|
CIFCurStyle->cs_reducer, 2 * CIFCurStyle->cs_expander);
|
|
|
|
|
|
|
|
|
|
if (def->cd_name != (char *) NULL)
|
|
|
|
|
if (def->cd_name[0] != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(def->cd_name, "(UNNAMED)") == 0)
|
|
|
|
|
fprintf(f, "9 UNNAMED;\n");
|
|
|
|
|
else {
|
|
|
|
|
if (CIFPathPrefix && CIFPathPrefix[0])
|
|
|
|
|
fprintf(f, "9 %s/%s;\n", CIFPathPrefix, def->cd_name);
|
|
|
|
|
else
|
|
|
|
|
fprintf(f, "9 %s;\n", def->cd_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Output all the tiles associated with this cell. Skip temporary
|
|
|
|
|
* layers.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
GEO_EXPAND(&def->cd_bbox, CIFCurStyle->cs_radius, &bigArea);
|
|
|
|
|
CIFErrorDef = def;
|
2020-11-12 16:34:27 +01:00
|
|
|
CIFGen(def, def, &bigArea, CIFPlanes, &DBAllTypeBits, TRUE, TRUE, FALSE,
|
|
|
|
|
(ClientData)NULL);
|
2023-03-07 17:16:49 +01:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!CIFHierWriteDisable)
|
2023-03-07 17:16:49 +01:00
|
|
|
CIFGenSubcells(def, &bigArea, CIFPlanes);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!CIFArrayWriteDisable)
|
2023-03-07 17:16:49 +01:00
|
|
|
CIFGenArrays(def, &bigArea, CIFPlanes);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (type = 0; type < CIFCurStyle->cs_nLayers; type++)
|
|
|
|
|
{
|
|
|
|
|
layer = CIFCurStyle->cs_layers[type];
|
|
|
|
|
if (layer->cl_flags & CIF_TEMP) continue;
|
|
|
|
|
cifPaintLayerName = layer->cl_name;
|
|
|
|
|
cifPaintScale = 1;
|
2021-11-16 16:58:18 +01:00
|
|
|
if (layer->cl_flags & CIF_LABEL)
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, CIFPlanes[type],
|
|
|
|
|
&TiPlaneRect, &CIFSolidBits, cifWriteLabelFunc,
|
|
|
|
|
(ClientData) f);
|
|
|
|
|
else
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, CIFPlanes[type],
|
|
|
|
|
&TiPlaneRect, &CIFSolidBits, cifWritePaintFunc,
|
|
|
|
|
(ClientData) f);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output labels */
|
|
|
|
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
|
|
|
|
{
|
|
|
|
|
int type = CIFCurStyle->cs_labelLayer[lab->lab_type];
|
|
|
|
|
Point center, size;
|
|
|
|
|
|
|
|
|
|
center.p_x = lab->lab_rect.r_xbot + lab->lab_rect.r_xtop;
|
|
|
|
|
center.p_y = lab->lab_rect.r_ybot + lab->lab_rect.r_ytop;
|
|
|
|
|
center.p_x *= CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
center.p_x /= CIFCurStyle->cs_reducer;
|
|
|
|
|
center.p_y *= CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
center.p_y /= CIFCurStyle->cs_reducer;
|
|
|
|
|
|
|
|
|
|
if (CIFDoAreaLabels)
|
|
|
|
|
{
|
|
|
|
|
size.p_x = lab->lab_rect.r_xtop - lab->lab_rect.r_xbot;
|
|
|
|
|
size.p_y = lab->lab_rect.r_ytop - lab->lab_rect.r_ybot;
|
|
|
|
|
size.p_x *= 2 * CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
size.p_x /= CIFCurStyle->cs_reducer;
|
|
|
|
|
size.p_y *= 2 * CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
size.p_y /= CIFCurStyle->cs_reducer;
|
|
|
|
|
if (type >= 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "95 %s %d %d %d %d %s;\n",
|
|
|
|
|
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y,
|
|
|
|
|
CIFCurStyle->cs_layers[type]->cl_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "95 %s %d %d %d %d;\n",
|
|
|
|
|
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (type >= 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "94 %s %d %d %s;\n",
|
|
|
|
|
lab->lab_text, center.p_x, center.p_y,
|
|
|
|
|
CIFCurStyle->cs_layers[type]->cl_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "94 %s %d %d;\n",
|
|
|
|
|
lab->lab_text, center.p_x, center.p_y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Output the calls that the child makes to its children. For
|
|
|
|
|
* arrays it is necessary to output one call for each instance.
|
|
|
|
|
*/
|
|
|
|
|
(void) DBCellEnum(def, cifWriteUseFunc, (ClientData) f);
|
|
|
|
|
fprintf(f, "DF;\n");
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifWriteUseFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function, called by DBCellEnum on behalf of cifOutFunc above,
|
|
|
|
|
* to write out each CellUse called by the CellDef being output.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always return 0
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Appends to the open CIF output file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifWriteUseFunc(
|
|
|
|
|
CellUse *use,
|
|
|
|
|
FILE *f)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int x, y, topx, topy;
|
|
|
|
|
int realx, realy;
|
|
|
|
|
Transform *t;
|
|
|
|
|
int cifnum;
|
|
|
|
|
|
|
|
|
|
cifnum = (int) use->cu_def->cd_client;
|
|
|
|
|
if (cifnum < 0) cifnum = (-cifnum);
|
|
|
|
|
topx = use->cu_xhi - use->cu_xlo;
|
|
|
|
|
if (topx < 0) topx = -topx;
|
|
|
|
|
topy = use->cu_yhi - use->cu_ylo;
|
|
|
|
|
if (topy < 0) topy = -topy;
|
|
|
|
|
realx = use->cu_xlo;
|
|
|
|
|
for (x = 0; x <= topx; x++)
|
|
|
|
|
{
|
|
|
|
|
realy = use->cu_ylo;
|
|
|
|
|
for (y = 0; y <= topy; y++)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We eventually want to tag each use with its unique
|
|
|
|
|
* use identifier, which should include array subscripting
|
|
|
|
|
* information.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* Insert a 91 user command to label the next cell
|
|
|
|
|
*/
|
|
|
|
|
if (CIFDoCellIdLabels && use->cu_id && use->cu_id[0]) {
|
|
|
|
|
fprintf (f, "91 %s", use->cu_id);
|
|
|
|
|
if (topx > 0 || topy > 0) {
|
|
|
|
|
if (topx > 0 && topy > 0)
|
|
|
|
|
fprintf (f, "(%d,%d)", realy, realx);
|
|
|
|
|
else {
|
|
|
|
|
if (topx > 0)
|
|
|
|
|
fprintf (f, "(%d)", realx);
|
|
|
|
|
else
|
|
|
|
|
fprintf (f, "(%d)", realy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fprintf (f, ";\n");
|
|
|
|
|
}
|
|
|
|
|
fprintf(f, "C %d", cifnum);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following translates from the abcdef transforms
|
|
|
|
|
* that we use internally to the rotate and mirror
|
|
|
|
|
* specs used in CIF. It only works because
|
|
|
|
|
* orientations are orthogonal in magic. Check all
|
|
|
|
|
* 8 possible positions if you don't believe this.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
t = &use->cu_transform;
|
|
|
|
|
if ((t->t_a != t->t_e) || ((t->t_a == 0) && (t->t_b == t->t_d)))
|
|
|
|
|
fprintf(f, " MX R %d %d", -(t->t_a), -(t->t_d));
|
|
|
|
|
else
|
|
|
|
|
fprintf(f, " R %d %d", t->t_a, t->t_d);
|
|
|
|
|
|
|
|
|
|
fprintf(f, " T %d %d;\n",
|
|
|
|
|
((t->t_c + t->t_a*(use->cu_xsep)*x + t->t_b*(use->cu_ysep)*y)
|
|
|
|
|
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer,
|
|
|
|
|
((t->t_f + t->t_d*(use->cu_xsep)*x + t->t_e*(use->cu_ysep)*y)
|
|
|
|
|
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer);
|
|
|
|
|
|
|
|
|
|
if (use->cu_yhi > use->cu_ylo)
|
|
|
|
|
realy++;
|
|
|
|
|
else
|
|
|
|
|
realy--;
|
|
|
|
|
}
|
|
|
|
|
if (use->cu_xhi > use->cu_xlo)
|
|
|
|
|
realx++;
|
|
|
|
|
else
|
|
|
|
|
realx--;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2021-11-16 16:58:18 +01:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifWriteLabelFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function used to write out a label corresponding to a
|
|
|
|
|
* single paint tile. The CIF layer name is used as the label to
|
|
|
|
|
* output.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always return 0
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes to the disk file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifWriteLabelFunc(
|
|
|
|
|
Tile *tile, /* Tile to be written out. */
|
|
|
|
|
FILE *f) /* File in which to write. */
|
2021-11-16 16:58:18 +01:00
|
|
|
{
|
|
|
|
|
Rect r;
|
|
|
|
|
int type;
|
|
|
|
|
Point center, size;
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile)) return 0; /* Ignore non-manhattan tiles */
|
|
|
|
|
|
|
|
|
|
if (cifPaintLayerName == NULL) return 0; /* Shouldn't happen */
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &r);
|
|
|
|
|
|
|
|
|
|
type = CIFCurStyle->cs_labelLayer[TiGetType(tile)];
|
|
|
|
|
|
|
|
|
|
center.p_x = r.r_xbot + r.r_xtop;
|
|
|
|
|
center.p_y = r.r_ybot + r.r_ytop;
|
|
|
|
|
center.p_x *= CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
center.p_x /= CIFCurStyle->cs_reducer;
|
|
|
|
|
center.p_y *= CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
center.p_y /= CIFCurStyle->cs_reducer;
|
|
|
|
|
|
|
|
|
|
if (CIFDoAreaLabels)
|
|
|
|
|
{
|
|
|
|
|
size.p_x = r.r_xtop - r.r_xbot;
|
|
|
|
|
size.p_y = r.r_ytop - r.r_ybot;
|
|
|
|
|
size.p_x *= 2 * CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
size.p_x /= CIFCurStyle->cs_reducer;
|
|
|
|
|
size.p_y *= 2 * CIFCurStyle->cs_scaleFactor;
|
|
|
|
|
size.p_y /= CIFCurStyle->cs_reducer;
|
|
|
|
|
fprintf(f, "95 %s %d %d %d %d;\n",
|
|
|
|
|
cifPaintLayerName, size.p_x, size.p_y, center.p_x, center.p_y);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "94 %s %d %d;\n",
|
|
|
|
|
cifPaintLayerName, center.p_x, center.p_y);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifWritePaintFunc --
|
|
|
|
|
*
|
|
|
|
|
* Filter function used to write out a single paint tile.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always return 0
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes to the disk file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifWritePaintFunc(
|
|
|
|
|
Tile *tile, /* Tile to be written out. */
|
|
|
|
|
FILE *f) /* File in which to write. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
Rect r;
|
|
|
|
|
|
|
|
|
|
/* Output the layer name if it hasn't been done already. */
|
|
|
|
|
|
|
|
|
|
if (cifPaintLayerName != NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, "L %s;\n", cifPaintLayerName);
|
|
|
|
|
cifPaintLayerName = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &r);
|
|
|
|
|
|
|
|
|
|
if (IsSplit(tile))
|
|
|
|
|
{
|
|
|
|
|
Point points[5];
|
|
|
|
|
int i, np;
|
|
|
|
|
|
|
|
|
|
GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile), points, &np);
|
|
|
|
|
|
|
|
|
|
/* Write triangle as a CIF polygon */
|
|
|
|
|
|
|
|
|
|
fprintf(f, " P");
|
|
|
|
|
for (i = 0; i < np; i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(f, " %d %d",
|
|
|
|
|
(2*cifPaintScale*(points[i].p_x))/CIFCurStyle->cs_reducer,
|
|
|
|
|
(2*cifPaintScale*(points[i].p_y))/CIFCurStyle->cs_reducer);
|
|
|
|
|
}
|
|
|
|
|
fprintf(f, ";\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
/* The only tricky thing here is that we MUST scale the rectangle
|
|
|
|
|
* up by a factor of two to avoid round-off errors in computing
|
|
|
|
|
* its center point (what a bogosity in CIF!!). This is compensated
|
|
|
|
|
* by shrinking by a factor of two in the "DS" statement.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fprintf(f, " B %d %d %d %d;\n",
|
|
|
|
|
(2*cifPaintScale*(r.r_xtop - r.r_xbot))/CIFCurStyle->cs_reducer,
|
|
|
|
|
(2*cifPaintScale*(r.r_ytop - r.r_ybot))/CIFCurStyle->cs_reducer,
|
|
|
|
|
(cifPaintScale*(r.r_xtop + r.r_xbot))/CIFCurStyle->cs_reducer,
|
|
|
|
|
(cifPaintScale*(r.r_ytop + r.r_ybot))/CIFCurStyle->cs_reducer);
|
|
|
|
|
CIFRects += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFWriteFlat --
|
|
|
|
|
*
|
|
|
|
|
* Write out the entire tree rooted at the supplied CellDef in CIF format,
|
2020-05-23 23:13:14 +02:00
|
|
|
* to the specified file, but write non-hierarchical CIF.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* Results:
|
|
|
|
|
* TRUE if the cell could be written successfully, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Writes a file to disk.
|
|
|
|
|
* In the event of an error while writing out the cell,
|
|
|
|
|
* the external integer errno is set to the UNIX error
|
|
|
|
|
* encountered.
|
|
|
|
|
*
|
|
|
|
|
* Algorithm:
|
|
|
|
|
* We operate on the cell in chunks chosen to keep the memory utilization
|
2020-05-23 23:13:14 +02:00
|
|
|
* reasonable. Foreach chunk, we use DBTreeSrTiles and cifHierCopyFunc to
|
|
|
|
|
* flatten the
|
|
|
|
|
* chunk into a yank buffer ("eliminating" the subcell problem), then use
|
2017-04-25 14:41:48 +02:00
|
|
|
* cifOut to generate the CIF.
|
|
|
|
|
* No hierarchical design rule checking or bounding box computation
|
|
|
|
|
* occur during this operation -- both are explicitly avoided.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFWriteFlat(
|
|
|
|
|
CellDef *rootDef, /* Pointer to CellDef to be written */
|
|
|
|
|
FILE *f) /* Open output file */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
bool good;
|
|
|
|
|
int oldCount = DBWFeedbackCount;
|
|
|
|
|
TileTypeBitMask cifMask;
|
|
|
|
|
SearchContext scx;
|
|
|
|
|
|
|
|
|
|
cifStack = StackNew(1);
|
|
|
|
|
CIFInitCells();
|
|
|
|
|
UndoDisable();
|
|
|
|
|
CIFDummyUse->cu_def = rootDef;
|
|
|
|
|
/*
|
|
|
|
|
* Write CIF preamble out first.
|
|
|
|
|
*/
|
|
|
|
|
cifOutPreamble(f, rootDef);
|
|
|
|
|
|
|
|
|
|
/*
|
2020-05-23 23:13:14 +02:00
|
|
|
* Now process each chunk. We cheat and use cifOut(), so we need to have
|
2017-04-25 14:41:48 +02:00
|
|
|
* a stack for the single flattened "component" to be on.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
scx.scx_use = CIFDummyUse;
|
|
|
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
|
|
|
GEO_EXPAND(&rootDef->cd_bbox, CIFCurStyle->cs_radius, &scx.scx_area);
|
|
|
|
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
|
|
|
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
|
|
|
|
DBReComputeBbox(CIFComponentDef);
|
|
|
|
|
cifCellNum = (-2);
|
|
|
|
|
CIFComponentDef->cd_client = (ClientData) -1;
|
|
|
|
|
StackPush((ClientData) CIFComponentDef, cifStack);
|
|
|
|
|
cifOut(f);
|
|
|
|
|
/* cifStack SHould be empty now */
|
|
|
|
|
if(!StackEmpty(cifStack))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Stack error in CIFWriteInverted()!! "
|
|
|
|
|
"Your CIF is probably corrupted.\n");
|
|
|
|
|
StackFree(cifStack);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
DBCellClearDef(CIFComponentDef);
|
|
|
|
|
}
|
|
|
|
|
StackFree(cifStack);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we are almost done.
|
|
|
|
|
* Just output a call on the root cell
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fprintf(f, "C %d;\nEnd\n", (int) CIFComponentDef->cd_client);
|
|
|
|
|
DBCellClearDef(CIFComponentDef);
|
|
|
|
|
good = !ferror(f);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Report any errors that occurred. */
|
|
|
|
|
|
|
|
|
|
if (DBWFeedbackCount != oldCount)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("%d problems occurred. See feedback entries.\n",
|
|
|
|
|
DBWFeedbackCount-oldCount);
|
|
|
|
|
}
|
|
|
|
|
return good;
|
|
|
|
|
}
|