Corrected the cell delete routine to include removing any elements

related to that cell (since elements are usually temporary and so
kept in a separate list, not in the cell).  Corrected a major error
in the bplane implementation that failed to remove a cell use from
the child def's parent list when deleting the use.  Can cause magic
to go into an infinite loop, especially after selecting and unselecting
cells.
This commit is contained in:
Tim Edwards 2020-05-15 20:49:51 -04:00
parent 028612b70a
commit fa60cbaaf0
6 changed files with 79 additions and 1 deletions

View File

@ -40,6 +40,7 @@
#include "utils/utils.h"
#include "utils/malloc.h"
#include "database/database.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "bplane/bplaneInt.h"
@ -180,6 +181,11 @@ void BPDelete(BPlane *bp, void *element)
Element *e = element;
ASSERT(e,"BPDelete");
if (bp->bp_count == 0)
{
TxError("Error: Attempt to delete instance from empty cell!\n");
return;
}
bp->bp_count--;
/* if element was on edge of bbox, bbox may no longer

View File

@ -65,6 +65,7 @@ dbInstanceUnplace(CellUse *use)
* or else we could leave the subcell tile plane in a weird
* state.
*/
BPDelete(use->cu_parent->cd_cellPlane, use);
}

View File

@ -30,6 +30,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "tiles/tile.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "dbwind/dbwind.h"
#include "utils/signals.h"
/* Forward declarations */
@ -214,6 +215,9 @@ DBCellClearDef(cellDef)
/* Remove all defined properties */
DBPropClearAll(cellDef);
/* Remove any elements associated with the cell */
DBWElementClearDef(cellDef);
SigEnableInterrupts();
}

View File

@ -811,7 +811,7 @@ DBClearCellPlane(def)
/* Do not use BPDelete() inside a BPEnum loop. Use DBSrCellUses */
/* to get a linked list of cell instances, then remove each one. */
DBSrCellUses(def, dbDeleteCellUse, (ClientData)NULL);
DBSrCellUses(def, dbDeleteCellUse, (ClientData)def);
SigEnableInterrupts();
}
@ -829,9 +829,32 @@ DBClearCellPlane(def)
int dbDeleteCellUse(CellUse *use, ClientData arg)
{
CellDef *def = (CellDef *)arg;
CellUse *defuses, *lastuse;
dbInstanceUnplace(use);
if (UndoIsEnabled())
DBUndoCellUse(use, UNDO_CELL_DELETE);
/* Remove use from cd_parents of the use's def */
lastuse = (CellUse *)NULL;
for (defuses = use->cu_def->cd_parents; defuses ; defuses = defuses->cu_nextuse)
{
if (defuses == use)
{
if (lastuse)
lastuse->cu_nextuse = defuses->cu_nextuse;
else
use->cu_def->cd_parents = defuses->cu_nextuse;
defuses->cu_nextuse = (CellUse *)NULL;
break;
}
lastuse = defuses;
}
if (use->cu_id) freeMagic(use->cu_id);
freeMagic(use);
return 0;
}

View File

@ -1239,3 +1239,46 @@ DBWElementPos(MagWindow *w, char *ename, Rect *crect)
elem->rootDef->cd_flags |= CDMODIFIED;
}
}
/*
* ----------------------------------------------------------------------------
*
* DBWElementClearDef --
*
* Removes all elements associated with the given CellDef.
*
* Results:
* None.
*
* Side effects:
* Elements are removed from the element hash.
*
* ----------------------------------------------------------------------------
*/
void
DBWElementClearDef(cellDef)
CellDef *cellDef;
{
DBWElement *elem;
HashEntry *entry;
styleptr stylePtr;
HashSearch hs;
HashStartSearch(&hs);
while ((entry = HashNext(&elementTable, &hs)) != NULL)
{
elem = (DBWElement *) HashGetValue(entry);
if (!elem) continue;
if (elem->rootDef != cellDef) continue;
for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next)
freeMagic(stylePtr);
if (elem->type == ELEMENT_TEXT)
freeMagic(elem->text);
HashSetValue(entry, NULL);
freeMagic(elem);
}
}

View File

@ -217,6 +217,7 @@ extern void DBWElementAddText();
extern void DBWElementDelete();
extern void DBWElementNames();
extern void DBWElementInbox();
extern void DBWElementClearDef();
extern void DBWElementParseFlags();
extern char *DBWPrintElements();
extern void DBWScaleElements();