#ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResMerge.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $"; #endif /* not lint */ #include #include "utils/magic.h" #include "utils/geometry.h" #include "utils/geofast.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/malloc.h" #include "textio/textio.h" #include "extract/extractInt.h" #include "resis/resis.h" TileTypeBitMask ResNoMergeMask[NT]; /* Forward declarations */ extern void ResMergeNodes(); extern void ResDeleteResPointer(); extern void ResEliminateResistor(); extern void ResCleanNode(); extern void ResFixBreakPoint(); /* *------------------------------------------------------------------------- * * ResDoneWithNode-- * After all connections to node are made, ResDoneWithNode is * called. It checks for parallel, series, loop, triangle, and * single conections, and simplifies the network where possible. * * Results: none * * Side Effects: deletes resistors and/or nodes. * *------------------------------------------------------------------------- */ void ResDoneWithNode(resptr) resNode *resptr; { int status; resNode *resptr2; resElement *rcell1; resResistor *rr1; resptr2 = NULL; resptr->rn_status |= TRUE; status = UNTOUCHED; /* are there any resistors? */ if (resptr->rn_re == NULL) return; /* Special handling for geometry option */ if (ResOptionsFlags & ResOpt_Geometry) return; /* Eliminate resistors with connections to one terminal and */ /* resistors with value 0. */ for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl) { rr1 = rcell1->re_thisEl; if (rr1->rr_connection1 == rr1->rr_connection2) { ResDeleteResPointer(resptr, rr1); ResDeleteResPointer(resptr, rr1); resptr->rn_float.rn_area += rr1->rr_float.rr_area; ResEliminateResistor(rr1, &ResResList); status = LOOP; ResDoneWithNode(resptr); break; } else if (rr1->rr_value == 0) { ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); if (rr1->rr_connection1 == resptr) resptr2 = rr1->rr_connection2; else resptr2 = rr1->rr_connection1; ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList); resptr2->rn_float.rn_area += rr1->rr_float.rr_area; ResEliminateResistor(rr1, &ResResList); if ((resptr2->rn_status & TRUE) == TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; status = SINGLE; break; } } if (status != UNTOUCHED) return; /* resptr may be invalid */ /* Eliminations that can be only if there are no devices connected */ /* to node. Series and dangling connections fall in this group. */ if ((resptr->rn_te == NULL) && (resptr->rn_why != RES_NODE_ORIGIN) && (status == UNTOUCHED)) status = ResSeriesCheck(resptr); if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN)) status = ResParallelCheck(resptr); if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN)) status = ResTriangleCheck(resptr); } /* *------------------------------------------------------------------------ * * ResFixRes-- * * Results: none * * Side Effects: ResFixRes combines two resistors in series. the second * Resistor is eliminated. Resptr is the node that is "cut out" of the * network. * *------------------------------------------------------------------------ */ void ResFixRes(resptr, resptr2, resptr3, elimResis, newResis) resNode *resptr, *resptr2, *resptr3; resResistor *elimResis, *newResis; { resElement *thisREl; resptr3->rn_float.rn_area += newResis->rr_value * resptr->rn_float.rn_area / ((float)(newResis->rr_value + elimResis->rr_value)); resptr2->rn_float.rn_area += elimResis->rr_value * resptr->rn_float.rn_area / ((float)(newResis->rr_value + elimResis->rr_value)); newResis->rr_value += elimResis->rr_value; ASSERT(newResis->rr_value > 0, "series"); newResis->rr_float.rr_area += elimResis->rr_float.rr_area; #ifdef ARIEL if (elimResis->rr_csArea && elimResis->rr_csArea < newResis->rr_csArea || newResis->rr_csArea == 0) { newResis->rr_csArea = elimResis->rr_csArea; newResis->rr_tt = elimResis->rr_tt; } #endif for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl) { if (thisREl->re_thisEl == elimResis) { (thisREl->re_thisEl = newResis); break; } } if (thisREl == NULL) TxError("Resistor not found in duo\n"); ResDeleteResPointer(resptr, elimResis); ResDeleteResPointer(resptr, newResis); ResEliminateResistor(elimResis, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); } /* *------------------------------------------------------------------------ * * ResFixParallel-- * * Results: none * * Side Effects: ResFixParallel combines two resistors in parallel. T * The second Resistor is eliminated. * * *------------------------------------------------------------------------ */ void ResFixParallel(elimResis, newResis) resResistor *elimResis, *newResis; { if ((newResis->rr_value + elimResis->rr_value) != 0) { newResis->rr_value = (((float) newResis->rr_value) * ((float)elimResis->rr_value)) / ((float)(newResis->rr_value + elimResis->rr_value)); ASSERT(newResis->rr_value >= 0, "parallel"); } else { newResis->rr_value = 0; } newResis->rr_float.rr_area += elimResis->rr_float.rr_area; #ifdef ARIEL newResis->rr_csArea += elimResis->rr_csArea; #endif ResDeleteResPointer(elimResis->rr_connection1, elimResis); ResDeleteResPointer(elimResis->rr_connection2, elimResis); ResEliminateResistor(elimResis, &ResResList); } /* *------------------------------------------------------------------------- * * ResSeriesCheck -- for nodes with no devices, sees if a series * or loop combination is possible. * * Results: returns SINGLE,LOOP,or SERIES if succesful. * * Side Effects: may delete some nodes and resistors. * *------------------------------------------------------------------------- */ int ResSeriesCheck(resptr) resNode *resptr; { resResistor *rr1,*rr2; resNode *resptr2, *resptr3; int status = UNTOUCHED; resElement *res_next; rr1 = resptr->rn_re->re_thisEl; res_next = resptr->rn_re->re_nextEl; if (res_next == NULL) /* node with only one connection */ { resptr2 = (rr1->rr_connection1 == resptr) ? rr1->rr_connection2: rr1->rr_connection1; ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); resptr2->rn_float.rn_area += rr1->rr_float.rr_area + resptr->rn_float.rn_area; ResEliminateResistor(rr1, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); status = SINGLE; if (resptr2->rn_status & TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; } else if (res_next->re_nextEl == NULL) { rr2 = res_next->re_thisEl; if (!TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt)) { if (rr1->rr_connection1 == resptr) { if (rr2->rr_connection1 == resptr) { resptr2 = rr1->rr_connection2; if (rr1->rr_connection2 == rr2->rr_connection2) { status = LOOP; ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); ResDeleteResPointer(rr2->rr_connection1, rr2); ResDeleteResPointer(rr2->rr_connection2, rr2); resptr2->rn_float.rn_area += rr1->rr_float.rr_area + rr2->rr_float.rr_area + resptr->rn_float.rn_area; ResEliminateResistor(rr1, &ResResList); ResEliminateResistor(rr2, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); } else { status = SERIES; resptr3 = rr2->rr_connection2; rr1->rr_connection1 = rr2->rr_connection2; ResFixRes(resptr, resptr2, resptr3, rr2, rr1); } if ((resptr2->rn_status & TRUE) == TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; } else { resptr2 = rr1->rr_connection2; if (rr1->rr_connection2 == rr2->rr_connection1) { status = LOOP; ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); ResDeleteResPointer(rr2->rr_connection1, rr2); ResDeleteResPointer(rr2->rr_connection2, rr2); resptr2->rn_float.rn_area += rr1->rr_float.rr_area + rr2->rr_float.rr_area + resptr->rn_float.rn_area; ResEliminateResistor(rr1, &ResResList); ResEliminateResistor(rr2, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); } else { status = SERIES; resptr3 = rr2->rr_connection1; rr1->rr_connection1 = rr2->rr_connection1; ResFixRes(resptr, resptr2, resptr3, rr2, rr1); } if ((resptr2->rn_status & TRUE) == TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; } } else { if (rr2->rr_connection1 == resptr) { resptr2 = rr1->rr_connection1; if (rr1->rr_connection1 == rr2->rr_connection2) { status = LOOP; ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); ResDeleteResPointer(rr2->rr_connection1, rr2); ResDeleteResPointer(rr2->rr_connection2, rr2); resptr2->rn_float.rn_area += rr1->rr_float.rr_area + rr2->rr_float.rr_area + resptr->rn_float.rn_area; ResEliminateResistor(rr1, &ResResList); ResEliminateResistor(rr2, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); } else { status = SERIES; resptr3 = rr2->rr_connection2; rr1->rr_connection2 = rr2->rr_connection2; ResFixRes(resptr, resptr2, resptr3, rr2, rr1); } if ((resptr2->rn_status & TRUE) == TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; } else { resptr2 = rr1->rr_connection1; if (rr1->rr_connection1 == rr2->rr_connection1) { status = LOOP; ResDeleteResPointer(rr1->rr_connection1, rr1); ResDeleteResPointer(rr1->rr_connection2, rr1); ResDeleteResPointer(rr2->rr_connection1, rr2); ResDeleteResPointer(rr2->rr_connection2, rr2); resptr2->rn_float.rn_area += rr1->rr_float.rr_area + rr2->rr_float.rr_area + resptr->rn_float.rn_area; ResEliminateResistor(rr1, &ResResList); ResEliminateResistor(rr2, &ResResList); ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue); } else { status = SERIES; resptr3 = rr2->rr_connection1; rr1->rr_connection2 = rr2->rr_connection1; ResFixRes(resptr, resptr2, resptr3, rr2, rr1); } if ((resptr2->rn_status & TRUE) == TRUE) { resptr2->rn_status &= ~TRUE; ResDoneWithNode(resptr2); } resptr2 = NULL; } } } } return status; } /* *------------------------------------------------------------------------- * * ResParallelCheck -- tries to do parallel combinations of devices. * * Results: returns PARALLEL if successful * * Side Effects: may delete resistors and nodes. * *------------------------------------------------------------------------- */ int ResParallelCheck(resptr) resNode *resptr; { resResistor *r1,*r2; resNode *resptr2,*resptr3; int status = UNTOUCHED; resElement *rcell1, *rcell2; for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL; rcell1 = rcell1->re_nextEl) { r1 = rcell1->re_thisEl; for (rcell2 = rcell1->re_nextEl; rcell2 != NULL; rcell2 = rcell2->re_nextEl) { r2 = rcell2->re_thisEl; if (TTMaskHasType(ResNoMergeMask+r1->rr_tt, r2->rr_tt)) continue; if (((r1->rr_connection1 == r2->rr_connection1) && (r1->rr_connection2 == r2->rr_connection2))|| ((r1->rr_connection1 == r2->rr_connection2) && (r1->rr_connection2 == r2->rr_connection1))) { resptr3 = (r1->rr_connection1 == resptr) ? r1->rr_connection2 : r1->rr_connection1; ResFixParallel(r1, r2); status = PARALLEL; resptr2 = NULL; if (resptr3->rn_status & TRUE) { resptr2 = resptr3; resptr2->rn_status &= ~TRUE; } ResDoneWithNode(resptr); if (resptr2 != NULL) ResDoneWithNode(resptr2); break; } } if (status == PARALLEL) break; } return status; } /* *------------------------------------------------------------------------- * * ResTriangleCheck -- looks for places to do the traingle-to-Y conversion. * * Results: returns TRIANGLE if successful. * * Side Effects: may allocate a new node. * *------------------------------------------------------------------------- */ int ResTriangleCheck(resptr) resNode *resptr; { resResistor *rr1, *rr2, *rr3; int status = UNTOUCHED; float r1, r2, r3, denom; resNode *n1, *n2, *n3; resElement *rcell1, *rcell2, *rcell3, *element; for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL; rcell1 = rcell1->re_nextEl) { rr1 = rcell1->re_thisEl; n1 = (rr1->rr_connection1 == resptr) ? rr1->rr_connection2: rr1->rr_connection1; for (rcell2 = rcell1->re_nextEl; rcell2 != NULL; rcell2 = rcell2->re_nextEl) { rr2 = rcell2->re_thisEl; if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt)) continue; n2 = (rr2->rr_connection1 == resptr) ? rr2->rr_connection2 : rr2->rr_connection1; for (rcell3 = n1->rn_re; rcell3 != NULL; rcell3 = rcell3->re_nextEl) { rr3 = rcell3->re_thisEl; if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr3->rr_tt)) continue; if (TTMaskHasType(ResNoMergeMask + rr2->rr_tt, rr3->rr_tt)) continue; if (((rr3->rr_connection1 != n1) || (rr3->rr_connection2 != n2)) && ((rr3->rr_connection2 != n1) || (rr3->rr_connection1 != n2))) continue; status = TRIANGLE; if ((denom = rr1->rr_value + rr2->rr_value + rr3->rr_value) != 0.0) { denom = 1.0 /denom; /* calculate new values for resistors */ r1 = (((float)rr1->rr_value) * ((float)rr2->rr_value)) * denom; r2 = (((float)rr2->rr_value) * ((float)rr3->rr_value)) * denom; r3 = (((float)rr1->rr_value) * ((float)rr3->rr_value)) * denom; rr1->rr_value = r1 + 0.5; rr2->rr_value = r2 + 0.5; rr3->rr_value = r3 + 0.5; ASSERT(rr1->rr_value >= 0, "Triangle"); ASSERT(rr2->rr_value >= 0, "Triangle"); ASSERT(rr3->rr_value >= 0, "Triangle"); } else { rr1->rr_value = 0; rr2->rr_value = 0; rr3->rr_value = 0; } n3 = (resNode *)mallocMagic((unsigned)(sizeof(resNode))); /* Where should the new node be put? It */ /* is arbitrarily assigned to the location */ /* occupied by the first node. */ InitializeNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE); n3->rn_status = FINISHED | TRUE | MARKED; n3->rn_less = NULL; n3->rn_more = ResNodeList; ResNodeList->rn_less = n3; ResNodeList = n3; if (resptr == rr1->rr_connection1) { ResDeleteResPointer(rr1->rr_connection2, rr1); rr1->rr_connection2 = n3; } else { ResDeleteResPointer(rr1->rr_connection1, rr1); rr1->rr_connection1 = n3; } if (n2 == rr2->rr_connection1) { ResDeleteResPointer(rr2->rr_connection2, rr2); rr2->rr_connection2 = n3; } else { ResDeleteResPointer(rr2->rr_connection1, rr2); rr2->rr_connection1 = n3; } if (n1 == rr3->rr_connection1) { ResDeleteResPointer(rr3->rr_connection2, rr3); rr3->rr_connection2 = n3; } else { ResDeleteResPointer(rr3->rr_connection1, rr3); rr3->rr_connection1 = n3; } element = (resElement *)mallocMagic((unsigned)(sizeof(resElement))); element->re_nextEl = NULL; element->re_thisEl = rr1; n3->rn_re = element; element = (resElement *)mallocMagic((unsigned)(sizeof(resElement))); element->re_nextEl = n3->rn_re; element->re_thisEl = rr2; n3->rn_re = element; element = (resElement *)mallocMagic((unsigned)(sizeof(resElement))); element->re_nextEl = n3->rn_re; element->re_thisEl = rr3; n3->rn_re = element; if ((n1->rn_status & TRUE) == TRUE) n1->rn_status &= ~TRUE; else n1 = NULL; if ((n2->rn_status & TRUE) == TRUE) n2->rn_status &= ~TRUE; else n2 = NULL; ResDoneWithNode(resptr); if (n1 != NULL) ResDoneWithNode(n1); if (n2 != NULL) ResDoneWithNode(n2); break; } if (status == TRIANGLE) break; } if (status == TRIANGLE) break; } return status; } /* *-------------------------------------------------------------------------- * * ResMergeNodes-- * * results: none * * side effects: appends all the cElement, jElement, tElement and * resElement structures from node 2 onto node 1. Node 2 is * then eliminated. * *--------------------------------------------------------------------------- */ void ResMergeNodes(node1, node2, pendingList, doneList) resNode *node1, *node2; resNode **pendingList, **doneList; { resElement *workingRes, *tRes; tElement *workingDev, *tDev; jElement *workingJunc, *tJunc; cElement *workingCon, *tCon; Tile *tile; int i; /* sanity check */ if (node1 == node2) return; if (node1 == NULL || node2 == NULL) { TxError("Attempt to merge NULL node\n"); return; } /* don't want to merge away startpoint */ if (node2->rn_why & RES_NODE_ORIGIN) node1->rn_why = RES_NODE_ORIGIN; /* set node resistance */ if (node1->rn_noderes > node2->rn_noderes) { node1->rn_noderes = node2->rn_noderes; if ((node1->rn_status & FINISHED) != FINISHED) { ResRemoveFromQueue(node1, pendingList); ResAddToQueue(node1, pendingList); } } node1->rn_float.rn_area += node2->rn_float.rn_area; /* combine relevant flags */ node1->rn_status |= (node2->rn_status & RN_MAXTDI); /* merge device lists */ workingDev = node2->rn_te; while (workingDev != NULL) { if (workingDev->te_thist->rd_status & RES_DEV_PLUG) { ResPlug *plug = (ResPlug *) workingDev->te_thist; if (plug->rpl_node == node2) plug->rpl_node = node1; else { TxError("Bad plug node: is (%d %d), should be (%d %d)\n", plug->rpl_node->rn_loc, node2->rn_loc); plug->rpl_node = NULL; } } else { int j; for (j = 0; j != workingDev->te_thist->rd_nterms; j++) if (workingDev->te_thist->rd_terminals[j] == node2) workingDev->te_thist->rd_terminals[j] = node1; } tDev = workingDev; workingDev = workingDev->te_nextt; tDev->te_nextt = node1->rn_te; node1->rn_te = tDev; } /* append junction lists */ workingJunc = node2->rn_je; while (workingJunc != NULL) { tJunc = workingJunc; for (i = 0; i < TILES_PER_JUNCTION; i++) { tileJunk *junk; tile = tJunc->je_thisj->rj_Tile[i]; junk = (tileJunk *) tile->ti_client; if ((junk->tj_status & RES_TILE_DONE) == FALSE) ResFixBreakPoint(&junk->breakList, node2, node1); } tJunc->je_thisj->rj_jnode = node1; workingJunc = workingJunc->je_nextj; tJunc->je_nextj = node1->rn_je; node1->rn_je = tJunc; } /* Append connection lists */ workingCon = node2->rn_ce; while (workingCon != NULL) { tCon = workingCon; for (i = 0; i < workingCon->ce_thisc->cp_currentcontact; i++) { if (workingCon->ce_thisc->cp_cnode[i] == node2) { tileJunk *junk; workingCon->ce_thisc->cp_cnode[i] = node1; tile =tCon->ce_thisc->cp_tile[i]; junk = (tileJunk *) tile->ti_client; if ((junk->tj_status & RES_TILE_DONE) == FALSE) ResFixBreakPoint(&junk->breakList, node2, node1); } } workingCon = workingCon->ce_nextc; tCon->ce_nextc = node1->rn_ce; node1->rn_ce = tCon; } /* Moves name to new node, if new node does not have a name */ if (node1->rn_name == NULL) node1->rn_name = node2->rn_name; /* Moves resistors to new node */ workingRes = node2->rn_re; while (workingRes != NULL) { if (workingRes->re_thisEl->rr_connection1 == node2) workingRes->re_thisEl->rr_connection1 = node1; else if (workingRes->re_thisEl->rr_connection2 == node2) workingRes->re_thisEl->rr_connection2 = node1; else TxError("Resistor not found.\n"); tRes = workingRes; workingRes = workingRes->re_nextEl; tRes->re_nextEl = node1->rn_re; node1->rn_re = tRes; } if ((node2->rn_status & FINISHED) == FINISHED) ResRemoveFromQueue(node2, doneList); else ResRemoveFromQueue(node2, pendingList); if (node2->rn_client != (ClientData)NULL) { freeMagic((char *)node2->rn_client); node2->rn_client = (ClientData)NULL; } node2->rn_re = (resElement *)CLIENTDEFAULT; node2->rn_ce = (cElement *)CLIENTDEFAULT; node2->rn_je = (jElement *)CLIENTDEFAULT; node2->rn_te = (tElement *)CLIENTDEFAULT; node2->rn_more = (resNode *)CLIENTDEFAULT; node2->rn_less = (resNode *)CLIENTDEFAULT; freeMagic((char *)node2); } /* *------------------------------------------------------------------------- * * ResDeleteResPointer-- Deletes the pointer from a node to a resistor. * Used when a resistor is deleted. * * Results:none * * Side Effects: Modifies a node's resistor list. * *------------------------------------------------------------------------- */ void ResDeleteResPointer(node,resistor) resNode *node; resResistor *resistor; { resElement *rcell1, *rcell2; int notfound = TRUE; rcell1 = NULL; rcell2 = node->rn_re; while (rcell2 != NULL) { if (rcell2->re_thisEl == resistor) { notfound = FALSE; if (rcell1 != NULL) rcell1->re_nextEl = rcell2->re_nextEl; else node->rn_re = rcell2->re_nextEl; /* Set fields to null just in case there are any stray */ /* pointers to structure. */ rcell2->re_thisEl = NULL; rcell2->re_nextEl = NULL; freeMagic((char *)rcell2); break; } rcell1 = rcell2; rcell2 = rcell2->re_nextEl; } if (notfound) TxError("Missing rptr at (%d %d).\n", node->rn_loc.p_x, node->rn_loc.p_y); } /* *------------------------------------------------------------------------- * * ResEliminateResistor-- * * Results:none * * Side Effects: Deletes a resistor. Does not delete pointers from nodes to * resistor. * *------------------------------------------------------------------------- */ void ResEliminateResistor(resistor, homelist) resResistor *resistor, **homelist; { if (resistor->rr_lastResistor == NULL) *homelist = resistor->rr_nextResistor; else resistor->rr_lastResistor->rr_nextResistor = resistor->rr_nextResistor; if (resistor->rr_nextResistor != NULL) resistor->rr_nextResistor->rr_lastResistor = resistor->rr_lastResistor; /* set everything to null so that any stray pointers will cause */ /* immediate death instead of a slow lingering one. */ resistor->rr_nextResistor = NULL; resistor->rr_lastResistor = NULL; resistor->rr_connection1 = NULL; resistor->rr_connection2 = NULL; freeMagic((char *)resistor); } /* *------------------------------------------------------------------------- * * ResCleanNode--removes the linked lists of junctions and contacts after * they are no longer needed. If the 'junk' option is used, * the node is eradicated. * * Results: * None. * * Side Effects: frees memory * *------------------------------------------------------------------------- */ void ResCleanNode(resptr, junk, homelist1, homelist2) resNode *resptr; int junk; resNode **homelist1; resNode **homelist2; { resElement *rcell; cElement *ccell; jElement *jcell; tElement *tcell; /* free up contact and junction lists */ while (resptr->rn_ce != NULL) { ccell = resptr->rn_ce; resptr->rn_ce = resptr->rn_ce->ce_nextc; freeMagic((char *)ccell); } while (resptr->rn_je != NULL) { jcell = resptr->rn_je; resptr->rn_je = resptr->rn_je->je_nextj; freeMagic((char *)jcell->je_thisj); freeMagic((char *)jcell); } if (junk == TRUE) { if (resptr->rn_client != (ClientData)NULL) { freeMagic((char *)resptr->rn_client); resptr->rn_client = (ClientData)NULL; } while (resptr->rn_te != NULL) { tcell = resptr->rn_te; resptr->rn_te = resptr->rn_te->te_nextt; freeMagic((char *)tcell); } while (resptr->rn_re != NULL) { rcell = resptr->rn_re; resptr->rn_re = resptr->rn_re->re_nextEl; freeMagic((char *)rcell); } if (resptr->rn_less != NULL) resptr->rn_less->rn_more = resptr->rn_more; else { if (*homelist1 == resptr) *homelist1 = resptr->rn_more; else if (*homelist2 == resptr) *homelist2 = resptr->rn_more; else TxError("Error: Attempted to eliminate node from wrong list.\n"); } if (resptr->rn_more != NULL) resptr->rn_more->rn_less = resptr->rn_less; resptr->rn_re = (resElement *) CLIENTDEFAULT; resptr->rn_ce = (cElement *) CLIENTDEFAULT; resptr->rn_je = (jElement *) CLIENTDEFAULT; resptr->rn_te = (tElement *) CLIENTDEFAULT; resptr->rn_more = (resNode *) CLIENTDEFAULT; resptr->rn_less = (resNode *) CLIENTDEFAULT; freeMagic((char *)resptr); } } /* *------------------------------------------------------------------------- * * ResFixBreakPoint--moves breakpoints from one node to another, checking * first to see whether the target node already has the breakpoint. * Used when nodes are merged. * * Results: none * * Side Effects: may free up memory if breakpoint is already present. * *------------------------------------------------------------------------- */ void ResFixBreakPoint(sourcelist, origNode, newNode) Breakpoint **sourcelist; resNode *origNode, *newNode; { Breakpoint *bp, *bp2, *bp3, *bp4; int alreadypresent; alreadypresent = FALSE; for (bp4 = *sourcelist; bp4 != NULL; bp4 = bp4->br_next) { if (bp4->br_this == newNode) { alreadypresent = TRUE; break; } } bp2 = NULL; bp = *sourcelist; while (bp != NULL) { if (bp->br_this == origNode) { if (alreadypresent) { if (bp2 == NULL) *sourcelist = bp->br_next; else bp2->br_next = bp->br_next; bp3 = bp; bp = bp->br_next; if (bp3->br_crect != NULL && bp4->br_crect == NULL) bp4->br_crect = bp3->br_crect; freeMagic((char *)bp3); continue; } else bp->br_this = newNode; } bp2 = bp; bp = bp->br_next; } }