1 
2 /* SimDBstuff.c -
3  *
4  *	This file contains routines that extract electrically connected
5  *	regions of a layout for Magic.   This extractor operates
6  *	hierarchically, across cell boundaries (SimTreeCopyConnect), as
7  *	well as within a single cell (SimSrConnect).
8  *
9  *	This also contains routines corresponding to those in the DBWind
10  *	module.
11  *
12  *     *********************************************************************
13  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
14  *     * Permission to use, copy, modify, and distribute this              *
15  *     * software and its documentation for any purpose and without        *
16  *     * fee is hereby granted, provided that the above copyright          *
17  *     * notice appear in all copies.  The University of California        *
18  *     * makes no representations about the suitability of this            *
19  *     * software for any purpose.  It is provided "as is" without         *
20  *     * express or implied warranty.  Export of this software outside     *
21  *     * of the United States of America may require an export license.    *
22  *     *********************************************************************
23  * University of California
24  */
25 
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "utils/magic.h"
30 #include "utils/geometry.h"
31 #include "utils/geofast.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "utils/stack.h"
35 #include "database/database.h"
36 #include "database/databaseInt.h"
37 #include "textio/textio.h"
38 #include "utils/signals.h"
39 #include "utils/malloc.h"
40 #include "extract/extractInt.h"
41 #include "sim/sim.h"
42 #include "windows/windows.h"
43 #include "dbwind/dbwind.h"
44 #include "commands/commands.h"
45 #include "textio/txcommands.h"
46 #include "utils/styles.h"
47 #include "graphics/graphics.h"
48 
49 /* Forward declarations */
50 
51 extern char *DBPrintUseId();
52 extern int  dbcUnconnectFunc();
53 extern void SimInitScxStk();
54 extern void SimPopScx();
55 extern void SimMakePathname();
56 
57 static char 		bestName[256];
58 
59 
60 /*
61  * ----------------------------------------------------------------------------
62  *
63  *	SimConnectFunc
64  *
65  *	This procedure is based upon the function dbcConnectFunc in the
66  *	database module.
67  *
68  * 	This procedure is invoked by SimTreeSrTiles from SimTreeCopyConnect,
69  *	whenever a tile is found that is connected to the current area
70  *	being processed.  If the tile overlaps the search area in a non-
71  *	trivial way (i.e. more than a 1x1 square of overlap at a corner)
72  *	then the area of the tile is added onto the list of things to check.
73  *	The "non-trivial" overlap check is needed to prevent caddy-corner
74  *	tiles from being considered as connected.
75  *
76  * Results:
77  *	Returns 0 normally, 1 if an abort condition has been encountered.
78  *
79  * Side effects:
80  *	Paints into the destination definition.
81  *
82  * ----------------------------------------------------------------------------
83  */
84 
85 int
SimConnectFunc(tile,cx)86 SimConnectFunc(tile, cx)
87     Tile *tile;			/* Tile found. */
88     TreeContext *cx;		/* Describes context of search.  The client
89 				 * data is a pointer to the list head of
90 				 * the conSrArg2's describing the areas
91 				 * left to check.
92 				 */
93 {
94     struct conSrArg2	*csa2;
95     Rect 		tileArea, *srArea, newarea;
96     SearchContext	*scx = cx->tc_scx;
97     TileTypeBitMask	notConnectMask, *connectMask;
98     TileType		loctype, ctype;
99     TileType		dinfo = 0;
100     int 		i, pNum;
101     static char		nodeName[256];
102     CellDef 		*def;
103     TerminalPath	*tpath = cx->tc_filter->tf_tpath;
104 
105     TiToRect(tile, &tileArea);
106     srArea = &scx->scx_area;
107 
108     if (((tileArea.r_xbot >= srArea->r_xtop-1) ||
109         (tileArea.r_xtop <= srArea->r_xbot+1)) &&
110 	((tileArea.r_ybot >= srArea->r_ytop-1) ||
111 	(tileArea.r_ytop <= srArea->r_ybot+1)))
112     {
113 	/* If the search area is only one unit wide or tall, then it's
114 	 * OK to have only a small overlap.  This happens only when
115 	 * looking for an initial search tile.
116 	 */
117 
118 	if (((srArea->r_xtop-1) != srArea->r_xbot)
119 		&& ((srArea->r_ytop-1) != srArea->r_ybot)) return 0;
120     }
121     GeoTransRect(&scx->scx_trans, &tileArea, &newarea);
122 
123     /* Clip the current area down to something that overlaps the
124      * area of interest.
125      */
126 
127     csa2 = (struct conSrArg2 *)cx->tc_filter->tf_arg;
128     GeoClip(&newarea, csa2->csa2_bounds);
129     if (GEO_RECTNULL(&newarea)) return 0;
130 
131     /* Stuff unique to the nodename search follows. */
132 
133     if (tpath != (TerminalPath *)NULL)
134     {
135         /* Extract the node name */
136 
137 	char *n = tpath->tp_next;
138 	char c = *n;
139 
140 	SigDisableInterrupts();
141 	strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, tpath->tp_first));
142 	SigEnableInterrupts();
143 
144 	*n = c;
145 
146 	/* save the "best" name for this node */
147 
148 	if (bestName[0] == '\0' || efPreferredName(nodeName, bestName))
149 	    strcpy(bestName, nodeName);
150     }
151 
152     loctype = TiGetTypeExact(tile);
153 
154     /* Resolve geometric transformations on diagonally-split tiles */
155 
156     if (IsSplit(tile))
157     {
158 	dinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
159 	loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
160     }
161 
162     /* See if the destination cell contains stuff over the whole
163      * current area (on its home plane) that is connected to it.
164      * If so, then there's no need to process the current area,
165      * since any processing that is needed was already done before.
166      */
167 
168     pNum = DBPlane(loctype);
169     connectMask = &csa2->csa2_connect[loctype];
170 
171     if (DBIsContact(loctype))
172     {
173 	TileTypeBitMask *rMask = DBResidueMask(loctype);
174 	TileTypeBitMask *cMask;
175 
176 	TTMaskSetOnlyType(&notConnectMask, loctype);
177 
178 	/* Differenct contact types may share residues (6/18/04) */
179 	for (ctype = TT_TECHDEPBASE; ctype < DBNumUserLayers; ctype++)
180 	{
181 	    if (DBIsContact(ctype))
182 	    {
183 		cMask = DBResidueMask(ctype);
184 		if (TTMaskIntersect(rMask, cMask))
185 		    TTMaskSetType(&notConnectMask, ctype);
186 	    }
187 	}
188 
189 	/* The mask of contact types must include all stacked contacts */
190 	for (ctype = DBNumUserLayers; ctype < DBNumTypes; ctype++)
191 	{
192 	    cMask = DBResidueMask(ctype);
193 	    if TTMaskHasType(cMask, loctype)
194 		TTMaskSetType(&notConnectMask, ctype);
195 	}
196 
197 	TTMaskCom(&notConnectMask);
198     }
199     else
200     {
201 	TTMaskCom2(&notConnectMask, connectMask);
202     }
203 
204     def = csa2->csa2_use->cu_def;
205     if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
206 		dinfo, &newarea, &notConnectMask, dbcUnconnectFunc,
207 		(ClientData) connectMask) == 0)
208 	return 0;
209 
210     /* Paint this tile into the destination cell. */
211 
212     DBNMPaintPlane(def->cd_planes[pNum], dinfo, &newarea,
213 		DBStdPaintTbl(loctype, pNum), (PaintUndoInfo *) NULL);
214 
215     /* Since the whole area of this tile hasn't been recorded,
216      * we must process its area to find any other tiles that
217      * connect to it.  Add each of them to the list of things
218      * to process.  We have to expand the search area by 1 unit
219      * on all sides because SimTreeSrTiles only returns things
220      * that overlap the search area, and we want things that
221      * even just touch.
222      */
223 
224     /* Only extend those sides bordering the diagonal tile */
225 
226     if (dinfo & TT_DIAGONAL)
227     {
228 	if (dinfo & TT_SIDE)			/* right */
229 	    newarea.r_xtop += 1;
230 	else					/* left */
231 	    newarea.r_xbot -= 1;
232 	if (((dinfo & TT_SIDE) >> 1)
233 		== (dinfo & TT_DIRECTION))	/* top */
234 	    newarea.r_ytop += 1;
235 	else					/* bottom */
236 	    newarea.r_ybot -= 1;
237     }
238     else
239     {
240 	newarea.r_xbot -= 1;
241 	newarea.r_ybot -= 1;
242 	newarea.r_xtop += 1;
243 	newarea.r_ytop += 1;
244     }
245 
246     /* Abort the name search if the name is in the abort name search table
247      * or if the name is global and the SimIgnoreGlobals flag is not set.
248      */
249 
250     if (SimSawAbortString  || SigInterruptPending)
251 	return 1;
252     else if (SimIsGetnode && !SimIgnoreGlobals)
253     {
254 	i = strlen(nodeName);
255 	if (nodeName[i - 1] == '!')
256 	    return 1;
257     }
258 
259     /* Check if any of the last 5 entries has the same type and */
260     /* area.  If so, don't duplicate the existing entry.        */
261     /* (NOTE:  Connect masks are all from the same table, so    */
262     /* they can be compared by address, no need for TTMaskEqual)*/
263 
264     for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--)
265         if (connectMask == csa2->csa2_list[i].connectMask)
266             if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea))
267                 return 0;
268 
269     /* Register the area and connection mask as needing to be processed */
270 
271     if (++csa2->csa2_top == CSA2_LIST_SIZE)
272     {
273 	/* Reached list size limit---need to enlarge the list	   */
274 	/* Double the size of the list every time we hit the limit */
275 
276 	conSrArea *newlist;
277 
278 	newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
279 	StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
280 	csa2->csa2_list = newlist;
281 	csa2->csa2_top = 0;
282     }
283 
284     csa2->csa2_list[csa2->csa2_top].area = newarea;
285     csa2->csa2_list[csa2->csa2_top].connectMask = connectMask;
286     csa2->csa2_list[csa2->csa2_top].dinfo = dinfo;
287     return 0;
288 }
289 
290 
291 /*
292  * ----------------------------------------------------------------------------
293  *
294  *	SimTreeCopyConnect
295  *
296  *	This procedure is very similar to DBTreeCopyConnect.
297  *
298  * 	This procedure copies connected information from a given cell
299  *	hierarchy to a given (flat) cell.  Starting from the tile underneath
300  *	the given area, this procedure finds all paint in all cells
301  *	that is connected to that information.  All such paint is
302  *	copied into the result cell.  If there are several electrically
303  *	distinct nets underneath the given area, one of them is picked
304  *	at more-or-less random.
305  *
306  *	Modified so the result cell is NOT first cleared of all paint.  This
307  *	allows multiple calls, to highlight incomplete routing nets.
308  *
309  * Results:
310  *	None.
311  *
312  * Side effects:
313  *	The contents of the result cell are modified.
314  *
315  * ----------------------------------------------------------------------------
316  */
317 
318 #define MAXPATHNAME 256
319 
320 void
SimTreeCopyConnect(scx,mask,xMask,connect,area,destUse,Node_Name)321 SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name)
322     SearchContext *scx;			/* Describes starting area.  The
323 					 * scx_use field gives the root of
324 					 * the hierarchy to search, and the
325 					 * scx_area field gives the starting
326 					 * area.  An initial tile must overlap
327 					 * this area.  The transform is from
328 					 * coords of scx_use to destUse.
329 					 */
330     TileTypeBitMask *mask;		/* Tile types to start from in area. */
331     int xMask;				/* Information must be expanded in all
332 					 * of the windows indicated by this
333 					 * mask.  Use 0 to consider all info
334 					 * regardless of expansion.
335 					 */
336     TileTypeBitMask *connect;		/* Points to table that defines what
337 					 * each tile type is considered to
338 					 * connect to.  Use DBConnectTbl as
339 					 * a default.
340 					 */
341     Rect *area;				/* The resulting information is
342 					 * clipped to this area.  Pass
343 					 * TiPlaneRect to get everything.
344 					 */
345     CellUse *destUse;			/* Result use in which to place
346 					 * anything connected to material of
347 					 * type mask in area of rootUse.
348 					 */
349     char *Node_Name;			/* Name of node returned.
350 					 * NOTE:  Don't call this "NodeName",
351 					 * because that conflicts with reserved
352 					 * words in some compilers.
353 					 */
354 {
355     TerminalPath tpath;
356     char pathName[MAXPATHNAME];
357     TileTypeBitMask *newmask;
358     struct conSrArg2 csa2;
359     TileType newtype;
360 
361     csa2.csa2_use = destUse;
362     csa2.csa2_bounds = area;
363     csa2.csa2_connect = connect;
364 
365     csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea));
366     csa2.csa2_top = -1;
367     csa2.csa2_lasttop = -1;
368 
369     csa2.csa2_stack = StackNew(100);
370 
371     tpath.tp_first = tpath.tp_next = pathName;
372     tpath.tp_last = pathName + MAXPATHNAME;
373 
374     pathName[0] = '\0';
375     bestName[0] = '\0';
376 
377     (void) SimTreeSrTiles(scx, mask, xMask, &tpath, SimConnectFunc,
378 		(ClientData) &csa2);
379     while (csa2.csa2_top >= 0)
380     {
381 	newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
382 	scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
383 	newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
384 	if (csa2.csa2_top == 0)
385 	{
386 	    if (StackLook(csa2.csa2_stack) != (ClientData)NULL)
387 	    {
388 		freeMagic(csa2.csa2_list);
389 		csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack);
390 		csa2.csa2_top = CSA2_LIST_SIZE - 1;
391 	    }
392 	    else
393 		csa2.csa2_top--;
394 	}
395 	else
396 	    csa2.csa2_top--;
397 
398 	csa2.csa2_lasttop = csa2.csa2_top;
399 
400 	if (newtype & TT_DIAGONAL)
401 	    SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath,
402 			SimConnectFunc, (ClientData) &csa2);
403 	else
404 	    SimTreeSrTiles(scx, newmask, xMask, &tpath, SimConnectFunc,
405 			(ClientData) &csa2);
406     }
407     freeMagic((char *)csa2.csa2_list);
408     StackFree(csa2.csa2_stack);
409 
410     /* Recompute the bounding box of the destination and record
411      * its area for redisplay.
412      */
413 
414     strcpy(Node_Name, bestName);
415     DBReComputeBbox(destUse->cu_def);
416 }
417 
418 /*
419  * ----------------------------------------------------------------------------
420  *
421  * efPreferredName --
422  *
423  * This is the same function used in the ext2sim module.  We need this
424  * function for the rsim interface to Magic.
425  *
426  * Determine which of two names is more preferred.  The most preferred
427  * name is a global name.  Given two non-global names, the one with the
428  * fewest pathname components is the most preferred.  If the two names
429  * have equally many pathname components, we choose the shortest.
430  *
431  * Results:
432  *	TRUE if 'name1' is preferable to 'name2', FALSE if not.
433  *
434  * Side effects:
435  *	None.
436  *
437  * ----------------------------------------------------------------------------
438  */
439 
440 bool
efPreferredName(name1,name2)441 efPreferredName(name1, name2)
442     char *name1, *name2;
443 {
444     int nslashes1, nslashes2;
445     char *np1, *np2;
446 
447     if( name1[0] == '@' && name1[1] == '=' )
448 	return( TRUE );
449     else if( name2[0] == '@' && name2[1] == '=' )
450 	return( FALSE );
451 
452     for (nslashes1 = 0, np1 = name1; *np1; ) {
453 	if (*np1++ == '/')
454 	    nslashes1++;
455     }
456 
457     for (nslashes2 = 0, np2 = name2; *np2; ) {
458 	if (*np2++ == '/')
459 	    nslashes2++;
460     }
461 
462     --np1;
463     --np2;
464 
465     if (!SimIgnoreGlobals)
466     {
467 	/* both are global names */
468 	if ((*np1 == '!') && (*np2 == '!')) {
469 	    /* check # of pathname components */
470 	    if (nslashes1 < nslashes2) return (TRUE);
471 	    if (nslashes1 > nslashes2) return (FALSE);
472 
473 	    /* same # of pathname components; check length */
474             if (np1 - name1 < np2 - name2) return (TRUE);
475     	    if (np1 - name1 > np2 - name2) return (FALSE);
476 
477 	    /* same # of pathname components; same length; use lex order */
478 	    if (strcmp(name1, name2) > 0)
479 		return(TRUE);
480 	    else
481 		return(FALSE);
482 	}
483 	if (*np1 == '!') return(TRUE);
484 	if (*np2 == '!') return(FALSE);
485     }
486 
487     /* neither name is global */
488     /* chose label over generated name */
489     if (*np1 != '#' && *np2 == '#') return (TRUE);
490     if (*np1 == '#' && *np2 != '#') return (FALSE);
491 
492     /* either both are labels or generated names */
493     /* check pathname components */
494     if (nslashes1 < nslashes2) return (TRUE);
495     if (nslashes1 > nslashes2) return (FALSE);
496 
497     /* same # of pathname components; check length */
498     if (np1 - name1 < np2 - name2) return (TRUE);
499     if (np1 - name1 > np2 - name2) return (FALSE);
500 
501     /* same # of pathname components; same length; use lex ordering */
502     if (strcmp(name1, name2) > 0)
503 	return(TRUE);
504     else
505 	return(FALSE);
506 }
507 
508 
509 
510 /*
511  * ----------------------------------------------------------------------------
512  *
513  *	SimSrConnect
514  *
515  *	This is similar to the procedure DBSrConnect, except that the
516  *	marks on each tile in the cell are not erased.
517  *
518  * 	Search through a cell to find all paint that is electrically
519  *	connected to things in a given starting area.
520  *
521  * Results:
522  *	0 is returned if the search finished normally.  1 is returned
523  *	if the search was aborted.
524  *
525  * Side effects:
526  *	The search starts from one (random) non-space tile in "startArea"
527  *	that matches the types in the mask parameter.  For every paint
528  *	tile that is electrically connected to the initial tile and that
529  *	intersects the rectangle "bounds", func is called.  Func should
530  *	have the following form:
531  *
532  *	    int
533  *	    func(tile, clientData)
534  *		Tile *tile;
535  *		ClientData clientData;
536  *    	    {
537  *	    }
538  *
539  *	The clientData passed to func is the same one that was passed
540  *	to us.  Func returns 0 under normal conditions;  if it returns
541  *	1 then the search is aborted.
542  *
543  *				*** WARNING ***
544  *
545  *	Func should not modify any paint during the search, since this
546  *	will mess up pointers kept by these procedures and likely cause
547  *	a core-dump.
548  *
549  * ----------------------------------------------------------------------------
550  */
551 
552 int
SimSrConnect(def,startArea,mask,connect,bounds,func,clientData)553 SimSrConnect(def, startArea, mask, connect, bounds, func, clientData)
554     CellDef *def;		/* Cell definition in which to carry out
555 				 * the connectivity search.  Only paint
556 				 * in this definition is considered.
557 				 */
558     Rect *startArea;		/* Area to search for an initial tile.  Only
559 				 * tiles OVERLAPPING the area are considered.
560 				 * This area should have positive x and y
561 				 * dimensions.
562 				 */
563     TileTypeBitMask *mask;	/* Only tiles of one of these types are used
564 				 * as initial tiles.
565 				 */
566     TileTypeBitMask *connect;	/* Pointer to a table indicating what tile
567 				 * types connect to what other tile types.
568 				 * Each entry gives a mask of types that
569 				 * connect to tiles of a given type.
570 				 */
571     Rect *bounds;		/* Area, in coords of scx->scx_use->cu_def,
572 				 * that limits the search:  only tiles
573 				 * overalapping this area will be returned.
574 				 * Use TiPlaneRect to search everywhere.
575 				 */
576     int (*func)();		/* Function to apply at each connected tile. */
577     ClientData clientData;	/* Client data for above function. */
578 
579 {
580     struct conSrArg csa;
581     int startPlane, result;
582     Tile *startTile;			/* Starting tile for search. */
583     extern int dbSrConnectFunc();	/* Forward declaration. */
584     extern int dbSrConnectStartFunc();
585 
586     result = 0;
587     csa.csa_def = def;
588     csa.csa_bounds = *bounds;
589 
590     /* Find a starting tile (if there are many tiles underneath the
591      * starting area, pick any one).  The search function just saves
592      * the tile address and returns.
593      */
594 
595     startTile = NULL;
596     for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
597     {
598 	if (DBSrPaintArea((Tile *) NULL,
599 	    def->cd_planes[startPlane], startArea, mask,
600 	    dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
601     }
602     if (startTile == NULL) return 0;
603 
604     /* Pass 1.  During this pass the client function gets called. */
605 
606     csa.csa_clientFunc = func;
607     csa.csa_clientData = clientData;
608     csa.csa_clear = FALSE;
609     csa.csa_connect = connect;
610     csa.csa_pNum = startPlane;
611     if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
612 
613     return result;
614 }
615 
616 
617 /*
618  *-----------------------------------------------------------------------------
619  *
620  * SimTreeSrTiles
621  *
622  * Similar to the procedure DBTreeSrTiles, although having a terminal
623  * path similar to procedure DBTreeSrLabels.
624  *
625  * Recursively search downward from the supplied CellUse for
626  * all visible paint tiles matching the supplied type mask.
627  *
628  * The procedure should be of the following form:
629  *	int
630  *	func(tile, cxp)
631  *	    Tile *tile;
632  *	    TreeContext *cxp;
633  *	{
634  *	}
635  *
636  * The SearchContext is stored in cxp->tc_scx, the user's arg is stored
637  * in cxp->tc_filter->tf_arg, and the terminal path is stored in
638  * cxp->tc_filter->tf_tpath.
639  *
640  * In the above, the scx transform is the net transform from the coordinates
641  * of tile to "world" coordinates (or whatever coordinates the initial
642  * transform supplied to SimTreeSrTiles was a transform to).  Func returns
643  * 0 under normal conditions.  If 1 is returned, it is a request to
644  * abort the search.
645  *
646  *			*** WARNING ***
647  *
648  * The client procedure should not modify any of the paint planes in
649  * the cells visited by SimTreeSrTiles, because we use DBSrPaintArea
650  * as our paint-tile enumeration function.
651  *
652  * Results:
653  *	0 is returned if the search finished normally.  1 is returned
654  *	if the search was aborted.
655  *
656  * Side effects:
657  *	Whatever side effects are brought about by applying the
658  *	procedure supplied.
659  *
660  *-----------------------------------------------------------------------------
661  */
662 
663 int
SimTreeSrTiles(scx,mask,xMask,tpath,func,cdarg)664 SimTreeSrTiles(scx, mask, xMask, tpath, func, cdarg)
665     SearchContext *scx;		/* Pointer to search context specifying
666 				 * a cell use to search, an area in the
667 				 * coordinates of the cell's def, and a
668 				 * transform back to "root" coordinates.
669 				 */
670     TileTypeBitMask *mask;	/* Only tiles with a type for which
671 				 * a bit in this mask is on are processed.
672 				 */
673     int xMask;			/* All subcells are visited recursively
674 				 * until we encounter uses whose flags,
675 				 * when anded with xMask, are not
676 				 * equal to xMask.
677 				 */
678     TerminalPath *tpath;	/* Pointer to a structure describing a
679 				 * partially filled-in terminal pathname.
680 				 * Add new components as encountered.
681 				 */
682     int (*func)();		/* Function to apply at each qualifying tile */
683     ClientData cdarg;		/* Client data for above function */
684 {
685     int SimCellTileSrFunc();
686     TreeFilter filter;
687 
688     filter.tf_func = func;
689     filter.tf_arg = cdarg;
690     filter.tf_mask = mask;
691     filter.tf_xmask = xMask;
692     filter.tf_planes = DBTechTypesToPlanes(mask);
693     filter.tf_tpath = tpath;
694     filter.tf_dinfo = 0;
695 
696     return SimCellTileSrFunc(scx, &filter);
697 }
698 
699 /*
700  * SimTreeSrNMTiles ---
701  *	This is a variant of the above in which the search is over
702  *	a non-Manhattan triangular area.
703  */
704 
705 int
SimTreeSrNMTiles(scx,dinfo,mask,xMask,tpath,func,cdarg)706 SimTreeSrNMTiles(scx, dinfo, mask, xMask, tpath, func, cdarg)
707     SearchContext *scx;		/* Pointer to search context specifying
708 				 * a cell use to search, an area in the
709 				 * coordinates of the cell's def, and a
710 				 * transform back to "root" coordinates.
711 				 */
712     TileType dinfo;		/* Type containing information about the
713 				 * triangular area to search.
714 				 */
715     TileTypeBitMask *mask;	/* Only tiles with a type for which
716 				 * a bit in this mask is on are processed.
717 				 */
718     int xMask;			/* All subcells are visited recursively
719 				 * until we encounter uses whose flags,
720 				 * when anded with xMask, are not
721 				 * equal to xMask.
722 				 */
723     TerminalPath *tpath;	/* Pointer to a structure describing a
724 				 * partially filled-in terminal pathname.
725 				 * Add new components as encountered.
726 				 */
727     int (*func)();		/* Function to apply at each qualifying tile */
728     ClientData cdarg;		/* Client data for above function */
729 {
730     int SimCellTileSrFunc();
731     TreeFilter filter;
732 
733     filter.tf_func = func;
734     filter.tf_arg = cdarg;
735     filter.tf_mask = mask;
736     filter.tf_xmask = xMask;
737     filter.tf_dinfo = dinfo;
738     filter.tf_planes = DBTechTypesToPlanes(mask);
739     filter.tf_tpath = tpath;
740 
741     return SimCellTileSrFunc(scx, &filter);
742 }
743 
744 /*
745  * Filter procedure applied to subcells by SimTreeSrTiles().
746  */
747 
748 int
SimCellTileSrFunc(scx,fp)749 SimCellTileSrFunc(scx, fp)
750     SearchContext *scx;
751     TreeFilter *fp;
752 {
753     TreeContext context;
754     TerminalPath *tp;
755     CellDef *def = scx->scx_use->cu_def;
756     int pNum, result;
757     char *tnext;
758 
759     ASSERT(def != (CellDef *) NULL, "SimCellTileSrFunc");
760     if (!DBDescendSubcell(scx->scx_use, fp->tf_xmask))
761 	return 0;
762     if ((def->cd_flags & CDAVAILABLE) == 0)
763     {
764 	bool dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
765 	if (!DBCellRead(def, (char *) NULL, TRUE, dereference, NULL)) return 0;
766     }
767 
768     context.tc_scx = scx;
769     context.tc_filter = fp;
770 
771     /* Create the path prefix */
772     /* Don't prepend the "Topmost cell" ID of the top-level cell. */
773 
774     if ((fp->tf_tpath != (TerminalPath *)NULL)
775 		&& (scx->scx_use->cu_parent != NULL))
776     {
777 	tp = fp->tf_tpath;
778 	tnext = tp->tp_next;
779 	tp->tp_next = DBPrintUseId(scx, tp->tp_next, tp->tp_last -
780 		tp->tp_next, FALSE);
781 	if (tp->tp_next < tp->tp_last)
782 	{
783 	    *(tp->tp_next++) = '/';
784 	    *(tp->tp_next) = '\0';
785 	}
786     }
787 
788     /*
789      * Apply the function first to any of the tiles in the planes
790      * for this CellUse's CellDef that match the mask.
791      */
792 
793     result = 0;
794     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
795 	if (PlaneMaskHasPlane(fp->tf_planes, pNum))
796 	{
797 	    if (fp->tf_dinfo & TT_DIAGONAL)
798 	    {
799 		TileType dinfo = DBTransformDiagonal(fp->tf_dinfo, &scx->scx_trans);
800 		if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
801 			dinfo, &scx->scx_area, fp->tf_mask,
802 			fp->tf_func, (ClientData) &context))
803 		{
804 		    result = 1;
805 		    goto cleanup;
806 		}
807 	    }
808 	    else
809 		if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
810 			&scx->scx_area, fp->tf_mask,
811 			fp->tf_func, (ClientData) &context))
812 		{
813 		    result = 1;
814 		    goto cleanup;
815 		}
816 	}
817 
818     /*
819      * Now apply ourselves recursively to each of the CellUses
820      * in our tile plane.
821      */
822 
823     if (DBCellSrArea(scx, SimCellTileSrFunc, (ClientData) fp))
824 	result = 1;
825 
826 cleanup:
827     /* Remove the trailing pathname component from the TerminalPath */
828     if ((fp->tf_tpath != (TerminalPath *)NULL)
829 		&& (scx->scx_use->cu_parent != NULL))
830     {
831 	fp->tf_tpath->tp_next = tnext;
832 	*tnext = '\0';
833     }
834     return (result);
835 }
836 
837 
838 /*
839  * ----------------------------------------------------------------------------
840  *
841  * SimPutLabel --
842  *
843  * Same as DBPutLabel, except this does not set the cell modified flag.
844  *
845  * Place a rectangular label in the database, in a particular cell.
846  *
847  * It is the responsibility of higher-level routines to insure that
848  * the material to which the label is being attached really exists at
849  * this point in the cell, and that TT_SPACE is used if there is
850  * no single material covering the label's entire area.  The routine
851  * DBAdjustLabels is useful for this.
852  *
853  * Results:
854  *	The return value is the actual alignment position used for
855  *	the label.  This may be different from align, if align is
856  *	defaulted.
857  *
858  * Side effects:
859  *	Updates the label list in the CellDef to contain the label.
860  *
861  * ----------------------------------------------------------------------------
862  */
863 
864 int
SimPutLabel(cellDef,rect,align,text,type)865 SimPutLabel(cellDef, rect, align, text, type)
866     CellDef *cellDef;	/* Cell in which label is placed */
867     Rect *rect;		/* Location of label; see above for description */
868     int align;		/* Orientation/alignment of text.  If this is < 0,
869 			 * an orientation will be picked to keep the text
870 			 * inside the cell boundary.
871 			 */
872     char *text;		/* Pointer to actual text of label */
873     TileType type;	/* Type of tile to be labeled */
874 {
875     Label *lab;
876     int len, x1, x2, y1, y2, tmp, labx, laby;
877 
878     len = strlen(text) + sizeof (Label) - sizeof lab->lab_text + 1;
879     lab = (Label *) mallocMagic((unsigned) len);
880     strcpy(lab->lab_text, text);
881 
882     /* Pick a nice alignment if the caller didn't give one.  If the
883      * label is more than BORDER units from an edge of the cell,
884      * use GEO_NORTH.  Otherwise, put the label on the opposite side
885      * from the boundary, so it won't stick out past the edge of
886      * the cell boundary.
887      */
888 
889 #define BORDER 5
890     if (align < 0)
891     {
892 	tmp = (cellDef->cd_bbox.r_xtop - cellDef->cd_bbox.r_xbot)/3;
893 	if (tmp > BORDER) tmp = BORDER;
894 	x1 = cellDef->cd_bbox.r_xbot + tmp;
895 	x2 = cellDef->cd_bbox.r_xtop - tmp;
896 	tmp = (cellDef->cd_bbox.r_ytop - cellDef->cd_bbox.r_ybot)/3;
897 	if (tmp > BORDER) tmp = BORDER;
898 	y1 = cellDef->cd_bbox.r_ybot + tmp;
899 	y2 = cellDef->cd_bbox.r_ytop - tmp;
900 	labx = (rect->r_xtop + rect->r_xbot)/2;
901 	laby = (rect->r_ytop + rect->r_ybot)/2;
902 
903 	if (labx <= x1)
904 	{
905 	    if (laby <= y1) align = GEO_NORTHEAST;
906 	    else if (laby >= y2) align = GEO_SOUTHEAST;
907 	    else align = GEO_EAST;
908 	}
909 	else if (labx >= x2)
910 	{
911 	    if (laby <= y1) align = GEO_NORTHWEST;
912 	    else if (laby >= y2) align = GEO_SOUTHWEST;
913 	    else align = GEO_WEST;
914 	}
915 	else
916 	{
917 	    if (laby <= y1) align = GEO_NORTH;
918 	    else if (laby >= y2) align = GEO_SOUTH;
919 	    else align = GEO_NORTH;
920 	}
921     }
922 
923     lab->lab_just = align;
924     lab->lab_type = type;
925     lab->lab_rect = *rect;
926     lab->lab_next = NULL;
927     lab->lab_flags = 0;
928     if (cellDef->cd_labels == NULL)
929 	cellDef->cd_labels = lab;
930     else
931     {
932 	ASSERT(cellDef->cd_lastLabel->lab_next == NULL, "SimPutLabel");
933 	cellDef->cd_lastLabel->lab_next = lab;
934     }
935     cellDef->cd_lastLabel = lab;
936 
937     DBUndoPutLabel(cellDef, lab);
938     return align;
939 }
940 
941 
942 #ifdef RSIM_MODULE
943 
944 /*
945  * ----------------------------------------------------------------------------
946  *
947  * SimRsimHandler
948  *
949  * 	This procedure is the button handler for the rsim tool.
950  *
951  * Results:
952  *	None.
953  *
954  * Side effects:
955  *	Left button:  used to move the whole box by the lower-left corner.
956  *	Right button: used to re-size the box by its upper-right corner.
957  *		If one of the left or right buttons is pushed, then the
958  *		other is pushed, the corner is switched to the nearest
959  *		one to the cursor.  This corner is remembered for use
960  *		in box positioning/sizing when both buttons have gone up.
961  *	Middle button: used to display the rsim node values of whatever
962  *		paint is selected.
963  *
964  * ----------------------------------------------------------------------------
965  */
966 
967 void
SimRsimHandler(w,cmd)968 SimRsimHandler(w, cmd)
969     MagWindow *w;			/* Window containing cursor. */
970     TxCommand *cmd;		/* Describes what happened. */
971 {
972 
973     static int buttonCorner = TOOL_ILG;
974     int button = cmd->tx_button;
975 
976     if (button == TX_MIDDLE_BUTTON)
977     {
978 	if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
979 	    SimRsimMouse(w);
980 	return;
981     }
982 
983     if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
984     {
985 	if ((WindNewButtons & (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
986 		== (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
987 	{
988 	    /* Both buttons are now down.  In this case, the FIRST
989 	     * button pressed determines whether we move or size,
990 	     * and the second button is just used as a signal to pick
991 	     * the closest corner.
992 	     */
993 
994 	    buttonCorner = ToolGetCorner(&cmd->tx_p);
995 	    if (button == TX_LEFT_BUTTON) button = TX_RIGHT_BUTTON;
996 	    else button = TX_LEFT_BUTTON;
997 	}
998 	else if (button == TX_LEFT_BUTTON) buttonCorner = TOOL_BL;
999 	else buttonCorner = TOOL_TR;
1000 	dbwButtonSetCursor(button, buttonCorner);
1001     }
1002     else
1003     {
1004 	/* A button has just come up.  If both buttons are down and one
1005 	 * is released, we just change the cursor to reflect the current
1006 	 * corner and the remaining button (i.e. move or size box).
1007 	 */
1008 
1009 	if (WindNewButtons != 0)
1010 	{
1011 	    if (button == TX_LEFT_BUTTON)
1012 		dbwButtonSetCursor(TX_RIGHT_BUTTON, buttonCorner);
1013 	    else dbwButtonSetCursor(TX_LEFT_BUTTON, buttonCorner);
1014 	    return;
1015 	}
1016 
1017 	/* The last button has been released.  Reset the cursor to normal
1018 	 * form and then move or size the box.
1019 	 */
1020 
1021 	GrSetCursor(STYLE_CURS_RSIM);
1022 	switch (button)
1023 	{
1024 	    case TX_LEFT_BUTTON:
1025 		ToolMoveBox(buttonCorner, &cmd->tx_p, TRUE, (CellDef *) NULL);
1026 		break;
1027 	    case TX_RIGHT_BUTTON:
1028 		ToolMoveCorner(buttonCorner, &cmd->tx_p, TRUE,
1029 			(CellDef *) NULL);
1030 	}
1031     }
1032 }
1033 
1034 #endif
1035