mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-28 17:15:13 +02:00
report it after "Failure to read in entire sub-tree". This will not report every failing cell (since it quits reading after the first failure) but will avoid the existing issue of printing nothing and leaving the user with no feedback as to which cell was the problem.
347 lines
9.9 KiB
C
347 lines
9.9 KiB
C
/*
|
|
* DBexpand.c --
|
|
*
|
|
* Expansion and unexpansion of cells
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBexpand.c,v 1.3 2010/08/15 14:35:47 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "database/databaseInt.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/stack.h"
|
|
|
|
/*
|
|
* Argument passed down to search functions when searching for
|
|
* cells to expand or unexpand.
|
|
*/
|
|
struct expandArg
|
|
{
|
|
bool ea_deref; /* TRUE if root def dereference flag is set */
|
|
int ea_xmask; /* Expand mask. */
|
|
int (*ea_func)(); /* Function to call for each cell whose
|
|
* status is changed.
|
|
*/
|
|
ClientData ea_arg; /* Argument to pass to func. */
|
|
};
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBExpand --
|
|
*
|
|
* Expand/unexpand a single CellUse.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* If expandFlag is TRUE, sets all the bits of expandMask in
|
|
* the flags of the given cellUse expandFlag is FALSE, clears
|
|
* all bits of expandMask.
|
|
*
|
|
* If expandFlag is TRUE and the cell being expanded has not
|
|
* been read in, reads it in from disk.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBExpand(cellUse, expandMask, expandFlag)
|
|
CellUse *cellUse;
|
|
int expandMask;
|
|
bool expandFlag;
|
|
{
|
|
CellDef *def;
|
|
|
|
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
|
|
return;
|
|
|
|
if (expandFlag)
|
|
{
|
|
def = cellUse->cu_def;
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
|
{
|
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
|
return;
|
|
/* Note: we don't have to recompute the bbox here, because
|
|
* if it changed, then a timestamp violation must have occurred
|
|
* and the timestamp manager will take care of recomputing
|
|
* the bbox.
|
|
*/
|
|
}
|
|
cellUse->cu_expandMask |= expandMask;
|
|
}
|
|
else
|
|
cellUse->cu_expandMask &= ~expandMask;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBExpandAll --
|
|
*
|
|
* Recursively expand/unexpand all cells which intersect or are
|
|
* contained within the given rectangle. Furthermore, if func is
|
|
* non-NULL, it is invoked for each cell whose status has changed,
|
|
* just after the change has been made. The calling sequence is
|
|
*
|
|
* int
|
|
* func(cellUse, cdarg)
|
|
* CellUse *cellUse;
|
|
* ClientData cdarg;
|
|
* {
|
|
* }
|
|
*
|
|
* In the calls to func, cellUse is the use whose expand bit has just
|
|
* been changed, and cdarg is the argument that the caller gave to us.
|
|
* Func should normally return 0. If it returns a non-zero value, then
|
|
* the call terminates immediately and no more cells are expanded.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* If expandFlag is TRUE, sets all the bits specified by
|
|
* expandMask in the flags of each CellUse found to intersect
|
|
* the given rectangle. If expandFlag is FALSE, clears all bits
|
|
* of expandMask.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
|
CellUse *rootUse; /* Root cell use from which search begins */
|
|
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
|
int expandMask; /* Window mask in which cell is to be expanded */
|
|
bool expandFlag; /* TRUE => expand, FALSE => unexpand */
|
|
int (*func)(); /* Function to call for each cell whose expansion
|
|
* status is modified. NULL means don't call anyone.
|
|
*/
|
|
ClientData cdarg; /* Argument to pass to func. */
|
|
{
|
|
int dbExpandFunc(), dbUnexpandFunc();
|
|
SearchContext scontext;
|
|
struct expandArg arg;
|
|
|
|
if ((rootUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
|
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
|
|
|
/*
|
|
* Walk through the area and set the expansion state
|
|
* appropriately.
|
|
*/
|
|
|
|
arg.ea_xmask = expandMask;
|
|
arg.ea_func = func;
|
|
arg.ea_arg = cdarg;
|
|
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
|
|
|
scontext.scx_use = rootUse;
|
|
scontext.scx_trans = GeoIdentityTransform;
|
|
scontext.scx_area = *rootRect;
|
|
if (expandFlag)
|
|
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
|
else
|
|
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
|
|
}
|
|
|
|
/*
|
|
* dbExpandFunc --
|
|
*
|
|
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
|
* when cells are being expanded.
|
|
*/
|
|
|
|
int
|
|
dbExpandFunc(scx, arg)
|
|
SearchContext *scx; /* Pointer to search context containing
|
|
* child use, search area in coor-
|
|
* dinates of the child use, and
|
|
* transform back to "root".
|
|
*/
|
|
struct expandArg *arg; /* Client data from caller */
|
|
{
|
|
CellUse *childUse = scx->scx_use;
|
|
int n = DBLambda[1];
|
|
|
|
/*
|
|
* Change the expansion status of this cell if necessary. Call the
|
|
* client's function if the expansion status has changed.
|
|
*/
|
|
|
|
if (!DBDescendSubcell(childUse, arg->ea_xmask))
|
|
{
|
|
/* If the cell is unavailable, then don't expand it.
|
|
*/
|
|
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
|
{
|
|
/* If the parent is dereferenced, then the child should be, too */
|
|
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
|
if(!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
|
{
|
|
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
|
childUse->cu_def->cd_name);
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
childUse->cu_expandMask |= arg->ea_xmask;
|
|
if (arg->ea_func != NULL)
|
|
{
|
|
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
|
}
|
|
}
|
|
|
|
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
|
return 1;
|
|
return 2;
|
|
}
|
|
|
|
/*
|
|
* dbUnexpandFunc --
|
|
*
|
|
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
|
* when cells are being unexpanded.
|
|
*/
|
|
|
|
int
|
|
dbUnexpandFunc(scx, arg)
|
|
SearchContext *scx; /* Pointer to search context containing
|
|
* child use, search area in coor-
|
|
* dinates of the child use, and
|
|
* transform back to "root".
|
|
*/
|
|
struct expandArg *arg; /* Client data from caller */
|
|
{
|
|
CellUse *childUse = scx->scx_use;
|
|
|
|
/*
|
|
* Change the expansion status of this cell if necessary.
|
|
*/
|
|
|
|
if (DBDescendSubcell(childUse, arg->ea_xmask))
|
|
{
|
|
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
|
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
|
|
{
|
|
childUse->cu_expandMask &= ~arg->ea_xmask;
|
|
|
|
/* Call the client's function, if there is one. */
|
|
|
|
if (arg->ea_func != NULL)
|
|
{
|
|
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Don't recursively search things that aren't already expanded. */
|
|
|
|
else return 2;
|
|
|
|
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
|
|
return 1;
|
|
return 2;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DBCellReadArea --
|
|
*
|
|
* Recursively read all cells which intersect or are contained within
|
|
* the given rectangle.
|
|
*
|
|
* Results:
|
|
* If "halt_on_error" is TRUE, then return a pointer to the first
|
|
* subcell that could not be read. Otherwise, return NULL.
|
|
*
|
|
* Side effects:
|
|
* May make new cells known to the database. Sets the CDAVAILABLE
|
|
* bit in all cells intersecting the search area.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
CellDef *
|
|
DBCellReadArea(rootUse, rootRect, halt_on_error)
|
|
CellUse *rootUse; /* Root cell use from which search begins */
|
|
Rect *rootRect; /* Area to be read, in root coordinates */
|
|
bool halt_on_error; /* If TRUE, failure to find a cell causes a halt */
|
|
{
|
|
int dbReadAreaFunc();
|
|
SearchContext scontext;
|
|
CellDef *err_def = NULL;
|
|
|
|
scontext.scx_use = rootUse;
|
|
scontext.scx_trans = GeoIdentityTransform;
|
|
scontext.scx_area = *rootRect;
|
|
if (dbReadAreaFunc(&scontext, ((halt_on_error == TRUE) ? &err_def : NULL)) == 1)
|
|
return err_def;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
dbReadAreaFunc(scx, err_ptr)
|
|
SearchContext *scx; /* Pointer to context specifying
|
|
* the cell use to be read in, and
|
|
* an area to be recursively read in
|
|
* coordinates of the cell use's def.
|
|
*/
|
|
CellDef **err_ptr; /* If non-NULL, failure to find a cell causes a halt
|
|
* and the CellDef in error is returned in err_def.
|
|
*/
|
|
{
|
|
CellDef *def = scx->scx_use->cu_def;
|
|
|
|
if ((def->cd_flags & CDAVAILABLE) == 0)
|
|
{
|
|
if (DBCellRead(def, TRUE, TRUE, NULL) == FALSE)
|
|
{
|
|
*err_ptr = def;
|
|
return 1;
|
|
}
|
|
|
|
/* Note: we don't have to invoke DBReComputeBbox here because
|
|
* if the bbox changed then there was a timestamp mismatch and
|
|
* the timestamp code will take care of the bounding box later.
|
|
*/
|
|
}
|
|
|
|
if (DBCellSrArea(scx, dbReadAreaFunc, (ClientData)err_ptr))
|
|
return 1;
|
|
|
|
/* Be clever about handling arrays: if the search area covers this
|
|
* whole definition, then there's no need to look at any other
|
|
* array elements, since we've already expanded the entire area
|
|
* of the definition.
|
|
*/
|
|
|
|
if (GEO_SURROUND(&scx->scx_area, &scx->scx_use->cu_def->cd_bbox))
|
|
return 2;
|
|
|
|
return 0;
|
|
}
|