1 /*
2  * DBtechpaint.c --
3  *
4  * Management of composition rules and the paint/erase tables.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtpaint.c,v 1.2 2010/06/08 19:16:42 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <string.h>	/* for memset(), memcpy() */
26 
27 #include "utils/magic.h"
28 #include "utils/geometry.h"
29 #include "utils/utils.h"
30 #include "tiles/tile.h"
31 #include "utils/hash.h"
32 #include "database/database.h"
33 #include "database/databaseInt.h"
34 #include "utils/tech.h"
35 #include "textio/textio.h"
36 
37     /* Painting and erasing tables */
38 PaintResultType DBPaintResultTbl[NP][NT][NT];
39 PaintResultType DBEraseResultTbl[NP][NT][NT];
40 PaintResultType DBWriteResultTbl[NT][NT];
41 PaintResultType DBSpecialResultTbl[NT];
42 
43 PlaneMask DBTypePaintPlanesTbl[NT];
44 PlaneMask DBTypeErasePlanesTbl[NT];
45 
46 /* ----------------- Data local to tech file processing --------------- */
47 
48 /*
49  * Tables telling which rules are default, and which have come
50  * from user-specified rules.  The bit is CLEAR if the type is
51  * a default type.
52  */
53 TileTypeBitMask dbNotDefaultEraseTbl[NT];
54 TileTypeBitMask dbNotDefaultPaintTbl[NT];
55 
56 /* --------------------- Data local to this file ---------------------- */
57 
58 int dbNumSavedRules = 0;
59 Rule dbSavedRules[NT];
60 
61 /* Forward declarations */
62 
63 extern void dbTechBitTypeInit();
64 
65 bool dbTechAddPaintErase();
66 bool dbTechSaveCompose();
67 
68 /*
69  * ----------------------------------------------------------------------------
70  *
71  * DBTechInitCompose --
72  *
73  * Initialize the painting and erasing rules prior to processing
74  * the "compose" section.  The rules for builtin types are computed
75  * here, as well as the default rules for all other types.  This
76  * procedure must be called after the "types" and "contacts" sections
77  * have been read, since we need to know about all existing tile types.
78  *
79  * Results:
80  *	None.
81  *
82  * Side effects:
83  *	Modifies the paint and erase tables.
84  *
85  * ----------------------------------------------------------------------------
86  */
87 
88 void
DBTechInitCompose()89 DBTechInitCompose()
90 {
91     TileType q, s, t, r;
92     int ps;
93     PaintResultType *stype, *dtype;
94     TileTypeBitMask *ttype;
95 
96     /* Default painting rules for error types */
97 
98     static TileType errorBitToType[] =
99     {
100 	TT_SPACE,	/* 0 */		TT_ERROR_P,	/* 1 */
101 	TT_ERROR_S,	/* 2 */		TT_ERROR_PS,	/* 3 */
102     };
103 
104     /* Painting and erasing are no-ops for undefined tile types */
105 
106     /* The following code is the FAST version using memcpy().	*/
107     /* See below for the actual slow loops.			*/
108 
109     stype = dtype = &(DBEraseResultTbl[0][0][0]);
110     for (ps = 0; ps < TT_MAXTYPES; ps++)
111 	*dtype++ = (PaintResultType)ps;
112     for (ps = 1; ps < PL_MAXTYPES * TT_MAXTYPES; ps++)
113     {
114 	memcpy((void *)dtype, (void *)stype, (size_t)TT_MAXTYPES
115 		* sizeof(PaintResultType));
116 	dtype += TT_MAXTYPES;
117     }
118 
119     /* Fast copy the entire erase table to the paint table memory */
120     dtype = &(DBPaintResultTbl[0][0][0]);
121     memcpy((void *)dtype, (void *)stype, (size_t)(TT_MAXTYPES
122 		* TT_MAXTYPES * PL_MAXTYPES * sizeof(PaintResultType)));
123 
124     /* The following code is dreadfully slow, but I'm leaving it */
125     /* in as a comment because it's easier to read.  The code	 */
126     /* above uses memory copying tricks to speed up the process. */
127     /*
128 
129     for (pNum = 0; pNum < PL_MAXTYPES; pNum++)
130     {
131 	for (s = 0; s < TT_MAXTYPES; s++)
132 	{
133 	    for (t = 0; t < TT_MAXTYPES; t++)
134 	    {
135 		/- Paint and erase are no-ops -/
136 		dbSetEraseEntry(s, t, pNum, s);
137 		dbSetPaintEntry(s, t, pNum, s);
138 	    }
139 	}
140     }
141 
142     for (s = 0; s < TT_MAXTYPES; s++)
143     {
144 	for (t = 0; t < TT_MAXTYPES; t++)
145 	{
146 	    /- Write overwrites existing contents -/
147 	    dbSetWriteEntry(s, t, t);
148 	}
149     }
150     */
151 
152 #if TT_MAXTYPES <= 256
153     /* For single-byte values, memset() is fastest. */
154 
155     dtype = &(DBWriteResultTbl[0][0]);
156     for (q = 0; q < TT_MAXTYPES; q++)
157     {
158 	memset((void *)dtype, (int)q, (size_t)TT_MAXTYPES);
159 	dtype += TT_MAXTYPES;
160     }
161 
162 #else
163     /* This is the slow loop, but it still faster than using	*/
164     /* macro dbSetWriteEntry().					*/
165 
166     dtype = &(DBWriteResultTbl[0][0]);
167     for (t = 0; t < TT_MAXTYPES; t++)
168 	for (s = 0; s < TT_MAXTYPES; s++)
169 	    *dtype++ = t;
170 
171 #endif
172 
173     /* All painting and erasing rules are default initially */
174 
175     /* This is also faster than the loop below. */
176 
177     ttype = &(dbNotDefaultEraseTbl[0]);
178     for (s = 0; s < DBNumTypes; s++) *ttype++ = DBZeroTypeBits;
179     ttype = &(dbNotDefaultPaintTbl[0]);
180     for (s = 0; s < DBNumTypes; s++) *ttype++ = DBZeroTypeBits;
181 
182     /*
183     for (s = 0; s < DBNumTypes; s++)
184     {
185 	dbNotDefaultEraseTbl[s] = DBZeroTypeBits;
186 	dbNotDefaultPaintTbl[s] = DBZeroTypeBits;
187     }
188     */
189 
190     /*
191      *	For each type t:
192      *	    erase(t, t, plane(t)) -> SPACE
193      *
194      *	For each type s, t:
195      *	    paint(s, t, plane(t)) -> t
196      *	    paint(s, t, ~plane(t)) -> s
197      */
198 
199     for (s = 0; s < DBNumTypes; s++)
200     {
201 	if ((ps = DBPlane(s)) > 0)
202 	{
203 	    for (t = 0; t < DBNumTypes; t++)
204 	    {
205 		if (DBPlane(t) > 0)
206 		{
207 		    r = (ps == DBPlane(t)) ? t : s;
208 		    dbSetEraseEntry(s, t, ps, s);
209 		    dbSetPaintEntry(s, t, ps, r);
210 		}
211 	    }
212 
213 	    /* Everything can be erased to space on its home plane */
214 	    dbSetEraseEntry(s, s, ps, TT_SPACE);
215 
216 	    /* Everything paints over space on its home plane */
217 	    dbSetPaintEntry(TT_SPACE, s, ps, s);
218 	}
219     }
220 
221     /*
222      * Special handling for check tile and error tile combinations.
223      */
224 #define	PCHK	PL_DRC_CHECK
225 #define	PERR	PL_DRC_ERROR
226 #define	tblsize(t)	( (sizeof (t)) / (sizeof (t[0])) )
227     dbTechBitTypeInit(errorBitToType, tblsize(errorBitToType), PERR, FALSE);
228 #undef	tblsize
229 
230     /*
231      * Paint results are funny for check plane because
232      * CHECKPAINT+CHECKSUBCELL = CHECKPAINT
233      */
234     dbSetPaintEntry(TT_SPACE, TT_CHECKPAINT, PCHK, TT_CHECKPAINT);
235     dbSetPaintEntry(TT_SPACE, TT_CHECKSUBCELL, PCHK, TT_CHECKSUBCELL);
236     dbSetPaintEntry(TT_CHECKPAINT, TT_CHECKSUBCELL, PCHK, TT_CHECKPAINT);
237     dbSetPaintEntry(TT_CHECKSUBCELL, TT_CHECKPAINT, PCHK, TT_CHECKPAINT);
238 #undef	PCHK
239 #undef	PERR
240 
241     /* Added 5/27/10:  Special table used for painting non-Manhattan	*/
242     /* tiles.  Uses TT_CHECKSUBCELL because that type does not exist on	*/
243     /* any paintable plane, and the checkpaint plane does not use non-	*/
244     /* manhattan tiles.							*/
245 
246     for (s = 0; s < DBNumTypes; s++) DBSpecialResultTbl[s] = TT_CHECKSUBCELL;
247 }
248 
249 /*
250  * ----------------------------------------------------------------------------
251  *
252  * dbTechBitTypeInit --
253  *
254  * Handle initialization of the paint and erase result tables for a
255  * set of ln2(n) primary types with n distinct mutual overlap types.
256  * The table bitToType points to a table containing n TileTypes
257  * (the overlap types) with the property that
258  *
259  *	bitToType[i] and bitToType[j] combine to yield bitToType[i | j]
260  *
261  * Also (unless composeFlag is set) erasing bitToType[j] from bitToType[i]
262  * gives bitToType[i & (~j)],
263  * i.e., it clears all of the j-type material out of the i-type material.
264  * The bitToType[k] for which k's binary representation has only a single
265  * bit set in it are the "primary" types.
266  *
267  * If composeFlag is set, the above is modified slightly to be analagous
268  * to compose rules, specifically, erase rules for nonprimary types are
269  * the default rules, i.e. they only erase precisely themselves.  This
270  * makes ":erase *-primary" work in the expected way.
271  *
272  * Results:
273  *	None.
274  *
275  * Side effects:
276  *	See above.
277  *
278  * ----------------------------------------------------------------------------
279  */
280 
281 void
dbTechBitTypeInit(bitToType,n,pNum,composeFlag)282 dbTechBitTypeInit(bitToType, n, pNum, composeFlag)
283     TileType *bitToType;
284     int n, pNum;
285     bool composeFlag;
286 {
287     int i, j;
288     TileType have, type;
289 
290     for (i = 0; i < n; i++)
291     {
292 	have = bitToType[i];
293 	for (j = 0; j < n; j++)
294 	{
295 	    type = bitToType[j];
296 	    dbSetPaintEntry(have, type, pNum, bitToType[i | j]);
297 	    if(!composeFlag || dbIsPrimary(j))
298 	    {
299 	        dbSetEraseEntry(have, type, pNum, bitToType[i & (~j)]);
300 	    }
301 	}
302     }
303 }
304 
305 /* Returns nonzero if exactly one bit set */
306 
307 int
dbIsPrimary(n)308 dbIsPrimary(n)
309     int n;
310 {
311     int bitCount;
312 
313     for(bitCount=0; n>0; n=n>>1)
314     {
315         if(n&1)
316         {
317 	    bitCount++;
318         }
319     }
320 
321     return (bitCount==1);
322 }
323 
324 
325 /*
326  * ----------------------------------------------------------------------------
327  *
328  * DBTechAddCompose --
329  *
330  * Process a single compose/erase rule.  If the type being described is
331  * a contact, save the rule and defer processing it until the end of this
332  * section, because we need to know the behavior of all non-contact types
333  * that might be residues before processing a contact composition rule.
334  * Rules for non-contact types are processed here.
335  *
336  * Results:
337  *	TRUE if successful, FALSE on error.
338  *
339  * Side effects:
340  *	Modifies the paint/erase tables if the type being described
341  *	is not a contact; otherwise, appends a rule to the list of
342  *	contact erase/compose rules for later processing.  Marks the
343  *	paint/erase table entries affected to show that they contain
344  *	user-specified rules instead of the default ones, so we don't
345  *	override them later.
346  *
347  * ----------------------------------------------------------------------------
348  */
349 
350     /*ARGSUSED*/
351 bool
DBTechAddCompose(sectionName,argc,argv)352 DBTechAddCompose(sectionName, argc, argv)
353     char *sectionName;
354     int argc;
355     char *argv[];
356 {
357     TileType type, r, s;
358     int pNum, ruleType, i;
359     static char *ruleNames[] =
360 	{ "compose", "decompose", "paint", "erase", 0 };
361     static int ruleTypes[] =
362 	{ RULE_COMPOSE, RULE_DECOMPOSE, RULE_PAINT, RULE_ERASE };
363 
364     if (argc < 4)
365     {
366 	TechError("Line must contain at least ruletype, result + pair\n");
367 	return FALSE;
368     }
369 
370     /* Look up and skip over type of rule */
371     i = Lookup(*argv, ruleNames);
372     if (i < 0)
373     {
374 	TechError("%s rule type %s.  Must be one of:\n\t",
375 		i == -1 ? "Ambiguous" : "Unknown", *argv);
376 	for (i = 0; ruleNames[i]; i++)
377 	    TxError("\"%s\" ", ruleNames[i]);
378 	TxError("\n");
379 	return FALSE;
380     }
381     ruleType = ruleTypes[i];
382     argv++, argc--;
383 
384     /* Paint or erase rules are processed specially */
385     switch (ruleType)
386     {
387 	case RULE_PAINT:
388 	case RULE_ERASE:
389 	    return (dbTechAddPaintErase(ruleType, sectionName, argc, argv));
390     }
391 
392     /* Compose or decompose rule: find result type and then skip over it */
393     if ((type = DBTechNoisyNameType(*argv)) < 0)
394 	return FALSE;
395     argv++, argc--;
396     if (argc & 01)
397     {
398 	TechError("Types on RHS of rule must be in pairs\n");
399 	return FALSE;
400     }
401 
402     /* Compose/decompose rules for contacts are saved away */
403     if (IsContact(type))
404 	return dbTechSaveCompose(ruleType, type, argc, argv);
405 
406     /* Rules for non-contacts are processed here */
407     for ( ; argc > 0; argc -= 2, argv += 2)
408     {
409 	if ((r = DBTechNoisyNameType(argv[0])) < 0
410 		|| (s = DBTechNoisyNameType(argv[1])) < 0)
411 	    return FALSE;
412 
413 	if (IsContact(r) || IsContact(s))
414 	{
415 	    TechError("Can't have contact layers on RHS of non-contact rule\n");
416 	    return FALSE;
417 	}
418 
419 	pNum = DBPlane(r);
420 	switch (ruleType)
421 	{
422 	    case RULE_COMPOSE:
423 		dbSetPaintEntry(r, s, pNum, type);
424 		dbSetPaintEntry(s, r, pNum, type);
425 		TTMaskSetType(&dbNotDefaultPaintTbl[r], s);
426 		TTMaskSetType(&dbNotDefaultPaintTbl[s], r);
427 		/* Fall through to */
428 	    case RULE_DECOMPOSE:
429 		dbSetPaintEntry(type, r, pNum, type);
430 		dbSetPaintEntry(type, s, pNum, type);
431 		dbSetEraseEntry(type, r, pNum, s);
432 		dbSetEraseEntry(type, s, pNum, r);
433 		TTMaskSetType(&dbNotDefaultPaintTbl[type], r);
434 		TTMaskSetType(&dbNotDefaultPaintTbl[type], s);
435 		TTMaskSetType(&dbNotDefaultEraseTbl[type], r);
436 		TTMaskSetType(&dbNotDefaultEraseTbl[type], s);
437 		break;
438 	}
439     }
440 
441     return TRUE;
442 }
443 
444 /*
445  * ----------------------------------------------------------------------------
446  *
447  * dbTechSaveCompose --
448  *
449  * Save a compose rule for a contact 't' in the table dbSavedRules.
450  * Check to make sure the rule is legal.
451  *
452  * Results:
453  *	Returns TRUE if successful, FALSE on error.
454  *
455  * Side effects:
456  *	Updates dbSavedRules[] and increments dbNumSavedRules.
457  *
458  * ----------------------------------------------------------------------------
459  */
460 
461 bool
dbTechSaveCompose(ruleType,t,argc,argv)462 dbTechSaveCompose(ruleType, t, argc, argv)
463     int ruleType;
464     TileType t;
465     int argc;
466     char *argv[];
467 {
468     TileType r, s;
469     Rule *rp;
470 
471     rp = &dbSavedRules[dbNumSavedRules++];
472     rp->r_ruleType = ruleType;
473     rp->r_result = t;
474     rp->r_npairs = 0;
475     for ( ; argc > 0; argc -= 2, argv += 2)
476     {
477 	r = DBTechNoisyNameType(argv[0]);
478 	s = DBTechNoisyNameType(argv[1]);
479 	if (r < 0 || s < 0)
480 	    return FALSE;
481 
482 	/* At most one of r and s may be a contact */
483 	if (IsContact(r) && IsContact(s))
484 	{
485 	    TechError("Only one type in each pair may be a contact\n");
486 	    return FALSE;
487 	}
488 
489 	/*
490 	 * The planes comprising 't' must be a superset of the
491 	 * planes comprising 'r' and the planes comprising 's'.
492 	 */
493 	if (((LayerPlaneMask(r) | LayerPlaneMask(s)) & ~LayerPlaneMask(t)) != 0)
494 	{
495 	    TechError("Component planes are a superset of result planes\n");
496 	    return FALSE;
497 	}
498 
499 	if (ruleType == RULE_COMPOSE)
500 	{
501 	    /* Types r and s can't appear on planes outside of t's */
502 	    if ((LayerPlaneMask(r) | LayerPlaneMask(s)) != LayerPlaneMask(t))
503 	    {
504 		TechError("Union of pair planes must = result planes\n");
505 		return FALSE;
506 	    }
507 
508 	    /* The following restriction has been lifted due to	*/
509 	    /* the recursive plane painting method added to	*/
510 	    /* routine DBPaint().	(Tim, 5/11/04)		*/
511 
512 //	    if (!dbTechCheckImages(t, r, s) || !dbTechCheckImages(t, s, r))
513 //		return FALSE;
514 	}
515 
516 	rp->r_pairs[rp->r_npairs].rp_a = r;
517 	rp->r_pairs[rp->r_npairs].rp_b = s;
518 	rp->r_npairs++;
519     }
520 
521     return TRUE;
522 }
523 
524 
525 #if 0	/* deprecated function (5/11/04) */
526 /*
527  * ----------------------------------------------------------------------------
528  *
529  * dbTechCheckImages --
530  *
531  * When processing a compose rule for 't' with RHS components
532  * 'r' and 's', check to be sure that the images of 't' on
533  * those planes present in 'r' but not in 's' are identical to
534  * the images of 'r' on those planes.  This is necessary in order
535  * that the result on these planes not depend on types present on
536  * other planes.
537  *
538  * Results:
539  *	Returns TRUE if successful, FALSE on error.
540  *
541  * Side effects:
542  *	None.
543  *
544  * ----------------------------------------------------------------------------
545  */
546 
547 bool
548 dbTechCheckImages(t, r, s)
549     TileType t;			/* Type that is composed */
550     TileType r;	/* First constituent */
551     TileType s;			/* Second constituent */
552 {
553     int pNum;
554     PlaneMask pMask;
555 
556     if (pMask = (LayerPlaneMask(r) & ~LayerPlaneMask(s)))
557     {
558 	for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
559 	    if (PlaneMaskHasPlane(pMask, pNum) && (t != r))
560 	    {
561 		TechError("Result image on plane %s must be the same "
562 			"as image of %s on plane %s\n",
563 			DBPlaneLongName(pNum),
564 			DBTypeLongName(r),
565 			DBPlaneLongName(pNum));
566 		return FALSE;
567 	    }
568     }
569 
570     return TRUE;
571 }
572 #endif	/* 0 */
573 
574 
575 /*
576  * ----------------------------------------------------------------------------
577  *
578  * dbTechAddPaintErase --
579  *
580  * Add a new entry to the paint or erase table.
581  * The semantics is that painting a tile of type1 with paint type2
582  * yields a tile of typeres.
583  *
584  * Results:
585  *	Returns TRUE if successful, FALSE on error.
586  *
587  * Side effects:
588  *	Updates the database technology variables.
589  *
590  * ----------------------------------------------------------------------------
591  */
592 
593 bool
dbTechAddPaintErase(type,sectionName,argc,argv)594 dbTechAddPaintErase(type, sectionName, argc, argv)
595     int type;
596     char *sectionName;
597     int argc;
598     char *argv[];
599 {
600     int pNum;
601     PlaneMask pMask, rMask;
602     TileType t1, t2, tres;
603     TileTypeBitMask tMask;
604 
605     if (argc < 3)
606     {
607 	TechError("Line must contain at least 3 types\n");
608 	return FALSE;
609     }
610 
611     if ((t1 = DBTechNoisyNameType(argv[0])) < 0) return FALSE;
612     if ((t2 = DBTechNoisyNameType(argv[1])) < 0) return FALSE;
613 
614     /* Modified 9/22/2020 to allow multiple types to paint, for example	*/
615     /* to replace a contact type with types on both residue planes.	*/
616 
617     rMask = DBTechNoisyNameMask(argv[2], &tMask);
618     if (TTMaskIsZero(&tMask)) return FALSE;
619 
620     if (argc == 3)
621     {
622 	if (t1 == TT_SPACE)
623 	{
624 	    TechError("<%s, %s, %s>:\n"
625 			"Must specify plane in paint table for "
626 			"painting space\n",
627 			argv[0], argv[1], argv[2]);
628 	    return FALSE;
629 	}
630 	else
631 	   pMask = LayerPlaneMask(t1);
632     }
633     else
634     {
635 	if ((pNum = DBTechNoisyNamePlane(argv[3])) < 0) return FALSE;
636 	else
637 	    pMask = PlaneNumToMaskBit(pNum);
638     }
639 
640     pMask &= ~rMask;
641 
642     /* 10/30/2020:  Changed from DBNumTypes to DBNumUserLayers,	    */
643     /* because DBTechNoisyNameMask() was modified to add stacking   */
644     /* contact types, and it is not correct for tMask to have more  */
645     /* than one type in the mask that share the same plane.	    */
646     /* NOTE:  Paint rules for stacked contacts probably have to be  */
647     /* handled too, but in a separate way.			    */
648 
649     for (tres = 0; tres < DBNumUserLayers; tres++)
650     {
651 	if (TTMaskHasType(&tMask, tres))
652 	{
653 	    if (type == RULE_PAINT)
654 	    {
655 		/* Apply to all planes of rMask. */
656 
657 		for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
658 		    if (PlaneMaskHasPlane(rMask, pNum))
659 			if (DBTypeOnPlane(tres, pNum))
660 			    dbSetPaintEntry(t1, t2, pNum, tres);
661 	    }
662 	    else	/* (type == RULE_ERASE) */
663 	    {
664 		/* Apply to all planes of rMask. */
665 
666 		for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
667 		    if (PlaneMaskHasPlane(rMask, pNum))
668 			if (DBTypeOnPlane(tres, pNum))
669 			    dbSetEraseEntry(t1, t2, pNum, tres);
670 	    }
671 	}
672     }
673 
674     if (type == RULE_PAINT)
675     {
676 	/* For all planes of pMask which are not in rMask, result is space */
677 
678 	for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
679 	    if (PlaneMaskHasPlane(pMask, pNum))
680 		    dbSetPaintEntry(t1, t2, pNum, TT_SPACE);
681     }
682     else	/* (type == RULE_ERASE) */
683     {
684 	/* For all planes of pMask which are not in rMask, result is space */
685 
686 	for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
687 	    if (PlaneMaskHasPlane(pMask, pNum))
688 		dbSetEraseEntry(t1, t2, pNum, TT_SPACE);
689     }
690     TTMaskSetType(&dbNotDefaultPaintTbl[t1], t2);
691     return TRUE;
692 }
693 
694 
695 /*
696  * ----------------------------------------------------------------------------
697  *
698  * dbTechCheckPaint --
699  *
700  * DEBUGGING.
701  * Check painting and erasing rules to make sure that the result
702  * type is legal for the plane being affected.
703  *
704  * Results:
705  *	None.
706  *
707  * Side effects:
708  *	Prints stuff in the event of an error.
709  *
710  * ----------------------------------------------------------------------------
711  */
712 
713 void
dbTechCheckPaint(where)714 dbTechCheckPaint(where)
715     char *where;	/* If non-null, print this as header */
716 {
717     TileType have, t, result;
718     bool printedHeader = FALSE;
719 
720     for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
721     {
722 	for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
723 	{
724 	    result = DBStdPaintEntry(have, t, DBPlane(have));
725 	    if (result != TT_SPACE && DBPlane(result) != DBPlane(have))
726 	    {
727 		if (!printedHeader && where)
728 		    TxPrintf("\n%s:\n", where), printedHeader = TRUE;
729 		TxPrintf("%s + %s -> %s\n",
730 			DBTypeShortName(have), DBTypeShortName(t),
731 			DBTypeShortName(result));
732 	    }
733 	    result = DBStdEraseEntry(have, t, DBPlane(have));
734 	    if (result != TT_SPACE && DBPlane(result) != DBPlane(have))
735 	    {
736 		if (!printedHeader && where)
737 		    TxPrintf("\n%s:\n", where), printedHeader = TRUE;
738 		TxPrintf("%s - %s -> %s\n",
739 			DBTypeShortName(have), DBTypeShortName(t),
740 			DBTypeShortName(result));
741 	    }
742 	}
743     }
744 }
745 
746 /*
747  * ----------------------------------------------------------------------------
748  *
749  * dbTechPrintPaint --
750  *
751  * DEBUGGING.
752  * Print painting and erasing rules.  If contactsOnly is TRUe, only
753  * print those rules involving pairs of contact types.  The argument
754  * "where" is printed as a header if it is non-NULL.  If doPaint is
755  * TRUE, we print the paint rules, else we print the erase rules.
756  *
757  * Results:
758  *	None.
759  *
760  * Side effects:
761  *	Prints stuff.
762  *
763  * ----------------------------------------------------------------------------
764  */
765 
766 void
dbTechPrintPaint(where,doPaint,contactsOnly)767 dbTechPrintPaint(where, doPaint, contactsOnly)
768     char *where;	/* If non-null, print this as header */
769     bool doPaint;	/* TRUE -> print paint tables, FALSE -> print erase */
770     bool contactsOnly;
771 {
772     TileType have, paint, erase, result;
773     int plane;
774     LayerInfo *lp;
775 
776     if (where)
777 	TxPrintf("\n%s:\n\n", where);
778 
779     if (doPaint)
780     {
781 	TxPrintf("PAINTING RULES:\n");
782 	for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
783 	{
784 	    if (contactsOnly && !IsContact(have)) continue;
785 	    for (paint = TT_TECHDEPBASE; paint < DBNumTypes; paint++)
786 	    {
787 		if (contactsOnly && !IsContact(paint)) continue;
788 		for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
789 		{
790 		    lp = &dbLayerInfo[have];
791 		    if (!PlaneMaskHasPlane(lp->l_pmask, plane))
792 			continue;
793 
794 		    result = DBStdPaintEntry(have, paint, plane);
795 		    if (result != have)
796 		    {
797 		        TxPrintf("%s ",
798 				DBTypeShortName(have));
799 			if (IsContact(have))
800 		            TxPrintf("(on %s) ",
801 					DBPlaneLongName(plane));
802 		        TxPrintf(" + %s -> %s\n",
803 				DBTypeShortName(paint),
804 				DBTypeShortName(result));
805 		    }
806 		}
807 	    }
808 	}
809     }
810     else
811     {
812 	TxPrintf("ERASING RULES:\n");
813 	for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
814 	{
815 	    if (contactsOnly && !IsContact(have)) continue;
816 	    for (erase = TT_TECHDEPBASE; erase < DBNumTypes; erase++)
817 	    {
818 		if (contactsOnly && !IsContact(erase)) continue;
819 		for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
820 		{
821 		    lp = &dbLayerInfo[have];
822 		    if (!PlaneMaskHasPlane(lp->l_pmask, plane))
823 			continue;
824 
825 		    result = DBStdEraseEntry(have, erase, plane);
826 		    if (result != have)
827 		    {
828 		        TxPrintf("%s ",
829 				DBTypeShortName(have));
830 			if (IsContact(have))
831 		            TxPrintf("(on %s) ",
832 					DBPlaneLongName(plane));
833 		        TxPrintf(" - %s -> %s\n",
834 				DBTypeShortName(erase),
835 				DBTypeShortName(result));
836 		    }
837 		}
838 	    }
839 	}
840     }
841 }
842