1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: drc.c
6  * Design-rule check tool
7  * WRitten by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "config.h"
33 #if DRCTOOL
34 
35 #include "global.h"
36 #include "egraphics.h"
37 #include "drc.h"
38 #include "efunction.h"
39 #include "tech.h"
40 #include "tecgen.h"
41 #include "tecschem.h"
42 #include "edialogs.h"
43 #include "usr.h"
44 #include "usrdiacom.h"
45 
46 /* the DRC tool table */
47 static COMCOMP dr_drccp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
48 	INPUTOPT, x_(" \t"), M_("cell to be rechecked"), M_("check current cell")};
49 static KEYWORD drcnotopt[] =
50 {
51 	{x_("verbose"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
52 	{x_("reasonable"),     0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
53 	TERMKEY
54 };
55 static COMCOMP drcnotp = {drcnotopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
56 	INPUTOPT, x_(" \t"), M_("Design Rule Checker negative action"), 0};
57 static COMCOMP drcfip = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
58 	INPUTOPT, x_(" \t"), M_("cell to ignored for short check DRC"), 0};
59 static COMCOMP drcfup = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
60 	INPUTOPT, x_(" \t"), M_("cell to un-ignored for short check DRC"), 0};
61 static KEYWORD drcfopt[] =
62 {
63 	{x_("select-run"),   0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
64 	{x_("run"),          0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
65 	{x_("ignore"),       1,{&drcfip,NOKEY,NOKEY,NOKEY,NOKEY}},
66 	{x_("unignore"),     1,{&drcfup,NOKEY,NOKEY,NOKEY,NOKEY}},
67 	TERMKEY
68 };
69 static COMCOMP drcfp = {drcfopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
70 	INPUTOPT, x_(" \t"), M_("Short Detecting Design Rule Checker action"), 0};
71 static KEYWORD drcnopt[] =
72 {
73 	{x_("run"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
74 	{x_("select-run"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
75 	{x_("reset-check-dates"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
76 	{x_("just-1-error"),      0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
77 	{x_("all-errors"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
78 	TERMKEY
79 };
80 static COMCOMP drcbatchp = {drcnopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
81 	INPUTOPT, x_(" \t"), M_("Batch Design Rule Checker action"), 0};
82 static KEYWORD drcopt[] =
83 {
84 	{x_("check"),                 1,{&dr_drccp,NOKEY,NOKEY,NOKEY,NOKEY}},
85 	{x_("forget-ignored-errors"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
86 	{x_("not"),                   1,{&drcnotp,NOKEY,NOKEY,NOKEY,NOKEY}},
87 	{x_("verbose"),               0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
88 	{x_("batch"),                 1,{&drcbatchp,NOKEY,NOKEY,NOKEY,NOKEY}},
89 	{x_("shortcheck"),            1,{&drcfp,NOKEY,NOKEY,NOKEY,NOKEY}},
90 	{x_("ecadcheck"),             0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
91 	{x_("reasonable"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
92 	{x_("quick-check"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
93 	{x_("quick-select-check"),    0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
94 	TERMKEY
95 };
96 COMCOMP dr_drcp = {drcopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
97 	0, x_(" \t"), M_("Design Rule Checker action"), M_("show defaults")};
98 
99 /* dcheck modules */
100 #define NODCHECK ((DCHECK *)-1)
101 
102 #define NODENEW    1					/* this nodeinst was created */
103 #define ARCNEW     2					/* this arcinst was created */
104 #define NODEMOD    3					/* this nodeinst was modified */
105 #define ARCMOD     4					/* this arcinst was modified */
106 #define NODEKILL   5					/* this nodeinst was deleted */
107 #define ARCKILL    6					/* this arcinst was deleted */
108 
109 typedef struct Idcheck
110 {
111 	NODEPROTO *cell;					/* cell containing object to be checked */
112 	INTBIG     entrytype;				/* type of check */
113 	void      *entryaddr;				/* object being checked */
114 	struct Idcheck *nextdcheck;			/* next in list */
115 } DCHECK;
116 static DCHECK   *dr_firstdcheck;
117 static DCHECK   *dr_dcheckfree;
118 
119 static INTBIG    dr_verbosekey;						/* key for "DRC_verbose" */
120        INTBIG    dr_ignore_listkey;					/* key for "DRC_ignore_list" */
121        INTBIG    dr_lastgooddrckey;					/* key for "DRC_last_good_drc" */
122 static INTBIG    dr_incrementalonkey;				/* key for "DRC_incrementalon" */
123 static INTBIG    dr_optionskey;						/* key for "DRC_options" */
124        INTBIG    dr_max_distanceskey;				/* key for "DRC_max_distances" */
125        INTBIG    dr_wide_limitkey;					/* key for "DRC_wide_limit" */
126        INTBIG    dr_min_widthkey;					/* key for "DRC_min_width" */
127        INTBIG    dr_min_width_rulekey;				/* key for "DRC_min_width_rule" */
128        INTBIG    dr_min_node_sizekey;				/* key for "DRC_min_node_size" */
129        INTBIG    dr_min_node_size_rulekey;			/* key for "DRC_min_node_size_rule" */
130        INTBIG    dr_connected_distanceskey;			/* key for "DRC_min_connected_distances" */
131        INTBIG    dr_connected_distances_rulekey;	/* key for "DRC_min_connected_distances_rule" */
132        INTBIG    dr_unconnected_distanceskey;		/* key for "DRC_min_unconnected_distances" */
133        INTBIG    dr_unconnected_distances_rulekey;	/* key for "DRC_min_unconnected_distances_rule" */
134        INTBIG    dr_connected_distancesWkey;		/* key for "DRC_min_connected_distances_wide" */
135        INTBIG    dr_connected_distancesW_rulekey;	/* key for "DRC_min_connected_distances_wide_rule" */
136        INTBIG    dr_unconnected_distancesWkey;		/* key for "DRC_min_unconnected_distances_wide" */
137        INTBIG    dr_unconnected_distancesW_rulekey;	/* key for "DRC_min_unconnected_distances_wide_rule" */
138        INTBIG    dr_connected_distancesMkey;		/* key for "DRC_min_connected_distances_multi" */
139        INTBIG    dr_connected_distancesM_rulekey;	/* key for "DRC_min_connected_distances_multi_rule" */
140        INTBIG    dr_unconnected_distancesMkey;		/* key for "DRC_min_unconnected_distances_multi" */
141        INTBIG    dr_unconnected_distancesM_rulekey;	/* key for "DRC_min_unconnected_distances_multi_rule" */
142        INTBIG    dr_edge_distanceskey;				/* key for "DRC_min_edge_distances" */
143        INTBIG    dr_edge_distances_rulekey;			/* key for "DRC_min_edge_distances_rule" */
144 #ifdef SURROUNDRULES
145        INTBIG    dr_surround_layer_pairskey;		/* key for "DRC_surround_layer_pairs" */
146        INTBIG    dr_surround_distanceskey;			/* key for "DRC_surround_distances" */
147 	   INTBIG    dr_surround_rulekey;				/* key for "DRC_surround_rule" */
148 #endif
149        BOOLEAN   dr_logerrors;						/* TRUE to log errors in error reporting system */
150        TOOL     *dr_tool;							/* the DRC tool object */
151 
152 CHAR *dr_variablenames[] =
153 {
154 	x_("DRC_max_distances"),
155 	x_("DRC_wide_limit"),
156 	x_("DRC_min_width"),
157 	x_("DRC_min_width_rule"),
158 	x_("DRC_min_node_size"),
159 	x_("DRC_min_node_size_rule"),
160 	x_("DRC_min_connected_distances"),
161 	x_("DRC_min_connected_distances_rule"),
162 	x_("DRC_min_unconnected_distances"),
163 	x_("DRC_min_unconnected_distances_rule"),
164 	x_("DRC_min_connected_distances_wide"),
165 	x_("DRC_min_connected_distances_wide_rule"),
166 	x_("DRC_min_unconnected_distances_wide"),
167 	x_("DRC_min_unconnected_distances_wide_rule"),
168 	x_("DRC_min_connected_distances_multi"),
169 	x_("DRC_min_connected_distances_multi_rule"),
170 	x_("DRC_min_unconnected_distances_multi"),
171 	x_("DRC_min_unconnected_distances_multi_rule"),
172 	x_("DRC_min_edge_distances"),
173 	x_("DRC_min_edge_distances_rule"),
174 	0
175 };
176 
177 /* prototypes for local routines */
178 static DCHECK    *dr_allocdcheck(void);
179 static NODEPROTO *dr_checkthiscell(INTBIG, CHAR*);
180 static void       dr_freedcheck(DCHECK*);
181 static void       dr_optionsdlog(void);
182 static void       dr_rulesdloghook(void);
183 static void       dr_queuecheck(void*, NODEPROTO*, INTBIG);
184 static void       dr_unignore(NODEPROTO*, BOOLEAN, void*);
185 static void       dr_unqueuecheck(LIBRARY *lib);
186 static INTBIG     dr_examinecell(NODEPROTO *np, BOOLEAN report);
187 static void       dr_schdocheck(GEOM *geom);
188 static void       dr_checkentirecell(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck,
189 					BOOLEAN *validity, BOOLEAN justarea);
190 static BOOLEAN    dr_schcheckcolinear(ARCINST *ai, ARCINST *oai);
191 static void       dr_schcheckobjectvicinity(GEOM *topgeom, GEOM *geom, XARRAY trans);
192 static void       dr_checkschematiccell(NODEPROTO *cell, BOOLEAN justthis);
193 static void       dr_checkschematiccellrecursively(NODEPROTO *cell);
194 static BOOLEAN    dr_schcheckpoly(GEOM *geom, POLYGON *poly, GEOM *otopgeom, GEOM *ogeom, XARRAY otrans, BOOLEAN cancross);
195 static BOOLEAN    dr_schcheckpolygonvicinity(GEOM *geom, POLYGON *poly);
196 static BOOLEAN    dr_checkpolyagainstpoly(GEOM *geom, POLYGON *poly, GEOM *ogeom, POLYGON *opoly, BOOLEAN cancross);
197 
198 /******************** CONTROL ********************/
199 
dr_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)200 void dr_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
201 {
202 	/* only initialize during pass 1 */
203 	if (thistool == NOTOOL || thistool == 0) return;
204 
205 	dr_tool = thistool;
206 
207 	/* initialize the design-rule checker lists */
208 	dr_dcheckfree = NODCHECK;
209 	dr_firstdcheck = NODCHECK;
210 	dr_logerrors = TRUE;
211 
212 	dr_verbosekey = makekey(x_("DRC_verbose"));
213 	dr_ignore_listkey = makekey(x_("DRC_ignore_list"));
214 	dr_lastgooddrckey = makekey(x_("DRC_last_good_drc"));
215 	dr_incrementalonkey = makekey(x_("DRC_incrementalon"));
216 	dr_optionskey = makekey(x_("DRC_options"));
217 	DiaDeclareHook(x_("drcopt"), &dr_drcp, dr_optionsdlog);
218 	DiaDeclareHook(x_("drcrules"), &dr_drccp, dr_rulesdloghook);
219 }
220 
dr_done(void)221 void dr_done(void)
222 {
223 #ifdef DEBUGMEMORY
224 	REGISTER DCHECK *d;
225 
226 	while (dr_firstdcheck != NODCHECK)
227 	{
228 		d = dr_firstdcheck;
229 		dr_firstdcheck = dr_firstdcheck->nextdcheck;
230 		dr_freedcheck(d);
231 	}
232 	while (dr_dcheckfree != NODCHECK)
233 	{
234 		d = dr_dcheckfree;
235 		dr_dcheckfree = dr_dcheckfree->nextdcheck;
236 		efree((CHAR *)d);
237 	}
238 	drcb_term();
239 	dr_quickterm();
240 #endif
241 }
242 
dr_set(INTBIG count,CHAR * par[])243 void dr_set(INTBIG count, CHAR *par[])
244 {
245 	REGISTER BOOLEAN negate;
246 	REGISTER INTBIG l, i, errs, options;
247 	REGISTER CHAR *pp;
248 	REGISTER FILE *f;
249 	REGISTER NODEPROTO *np;
250 	REGISTER VARIABLE *var;
251 	REGISTER TECHNOLOGY *tech;
252 	CHAR *newpar[3], *truename, *abortseq;
253 	static INTBIG filetypedrac = -1;
254 	REGISTER void *infstr;
255 
256 	if (count == 0)
257 	{
258 		var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_verbosekey);
259 		if (var == NOVARIABLE) i = 0; else i = var->addr;
260 		if (i == 0) ttyputmsg(M_("Design rule checker is brief")); else
261  			ttyputmsg(M_("Design rule checker is verbose"));
262 		return;
263 	}
264 
265 	options = dr_getoptionsvalue();
266 	l = estrlen(pp = par[0]);
267 	negate = FALSE;
268 	if (namesamen(pp, x_("not"), l) == 0)
269 	{
270 		negate = TRUE;
271 		if (count <= 1)
272 		{
273 			count = ttygetparam(M_("DRC negate option:"), &drcnotp, MAXPARS-1, &par[1]) + 1;
274 			if (count <= 1)
275 			{
276 				ttyputerr(M_("Aborted"));
277 				return;
278 			}
279 		}
280 		l = estrlen(pp = par[1]);
281 	}
282 
283 	if (namesamen(pp, x_("forget-ignored-errors"), l) == 0)
284 	{
285 		np = dr_checkthiscell(count, par[1]);
286 		if (np == NONODEPROTO) return;
287 
288 		/* erase all ignore lists on all objects */
289 		var = getvalkey((INTBIG)np, VNODEPROTO, VGEOM|VISARRAY, dr_ignore_listkey);
290 		if (var != NOVARIABLE)
291 			(void)delvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey);
292 
293 		ttyputmsg(M_("Ignored violations turned back on."));
294 		return;
295 	}
296 	if (namesamen(pp, x_("check"), l) == 0)
297 	{
298 		/* make sure network tool is on */
299 		if ((net_tool->toolstate&TOOLON) == 0)
300 		{
301 			ttyputerr(M_("Network tool must be running...turning it on"));
302 			toolturnon(net_tool);
303 			ttyputerr(M_("...now reissue the DRC command"));
304 			return;
305 		}
306 
307 		np = dr_checkthiscell(count, par[1]);
308 		if (np == NONODEPROTO) return;
309 		errs = dr_examinecell(np, TRUE);
310 		return;
311 	}
312 
313 	if (namesamen(pp, x_("ecadcheck"), l) == 0)
314 	{
315 		np = getcurcell();
316 		if (np == NONODEPROTO)
317 		{
318 			ttyputerr(_("Must be editing a cell to check with ECAD's Dracula"));
319 			return;
320 		}
321 		tech = np->tech;
322 		var = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("DRC_ecad_deck"));
323 		if (var == NOVARIABLE)
324 		{
325 			ttyputerr(_("Cannot find an ECAD deck in the %s technology"), tech->techname);
326 			return;
327 		}
328 
329 		/* create the file */
330 		if (filetypedrac < 0)
331 			filetypedrac = setupfiletype(x_("rul"), x_("*.map"), MACFSTAG('TEXT'), FALSE, x_("drac"), _("Dracula"));
332 		f = xcreate(x_("ecaddrc.RUL"), filetypedrac, _("ECAD DRC Control File"), &truename);
333 		if (f == NULL)
334 		{
335 			if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
336 			return;
337 		}
338 
339 		/* write the deck */
340 		l = getlength(var);
341 		for(i=0; i<l; i++)
342 		{
343 			pp = ((CHAR **)var->addr)[i];
344 			if (estrncmp(pp, x_(" PRIMARY ="), 10) == 0)
345 			{
346 				xprintf(f, x_(" PRIMARY = %s\n"), np->protoname);
347 				continue;
348 			}
349 			if (estrncmp(pp, x_(" INDISK ="), 9) == 0)
350 			{
351 				xprintf(f, x_(" INDISK = %s.cif\n"), np->protoname);
352 				continue;
353 			}
354 			xprintf(f, x_("%s\n"), pp);
355 		}
356 
357 		/* finished with control deck */
358 		xclose(f);
359 		ttyputverbose(M_("Wrote 'ecaddrc.RUL'.  Now generating CIF for cell %s"), describenodeproto(np));
360 
361 		/* tell I/O to write CIF */
362 		newpar[0] = x_("cif");
363 		newpar[1] = x_("output");
364 		newpar[2] = x_("include-cloak-layer");
365 		telltool(io_tool, 3, newpar);
366 		(void)asktool(io_tool, x_("write"), (INTBIG)np->lib, (INTBIG)x_("cif"));
367 		newpar[0] = x_("cif");
368 		newpar[1] = x_("output");
369 		newpar[2] = x_("ignore-cloak-layer");
370 		telltool(io_tool, 3, newpar);
371 		return;
372 	}
373 
374 	if (namesamen(pp, x_("batch"), l) == 0)
375 	{
376 		if (count == 1)
377 		{
378 			ttyputusage(x_("telltool drc batch OPTIONS"));
379 			return;
380 		}
381 		l = estrlen(pp = par[1]);
382 		if (namesamen(pp, x_("run"), l) == 0)
383 		{
384 			/* make sure network tool is on */
385 			if ((net_tool->toolstate&TOOLON) == 0)
386 			{
387 				ttyputerr(M_("Network tool must be running...turning it on"));
388 				toolturnon(net_tool);
389 				ttyputerr(M_("...now reissue the DRC command"));
390 				return;
391 			}
392 
393 			/* make sure there is a cell to check */
394 			np = getcurcell();
395 			if (np == NONODEPROTO)
396 			{
397 				ttyputerr(_("No current cell"));
398 				return;
399 			}
400 
401 			/* see if a dialog should be displayed */
402 			infstr = initinfstr();
403 			addstringtoinfstr(infstr, _("Checking hierarchically..."));
404 			abortseq = getinterruptkey();
405 			if (abortseq != 0)
406 				formatinfstr(infstr, _(" (type %s to abort)"), abortseq);
407 			ttyputmsg(returninfstr(infstr));
408 			(void)drcb_check(np, TRUE, FALSE);
409 			return;
410 		}
411 		if (namesamen(pp, x_("select-run"), l) == 0)
412 		{
413 			/* make sure network tool is on */
414 			if ((net_tool->toolstate&TOOLON) == 0)
415 			{
416 				ttyputerr(M_("Network tool must be running...turning it on"));
417 				toolturnon(net_tool);
418 				ttyputerr(M_("...now reissue the DRC command"));
419 				return;
420 			}
421 
422 			/* make sure there is a cell to check */
423 			np = getcurcell();
424 			if (np == NONODEPROTO)
425 			{
426 				ttyputerr(_("No current cell"));
427 				return;
428 			}
429 
430 			/* see if a dialog should be displayed */
431 			infstr = initinfstr();
432 			addstringtoinfstr(infstr, _("Checking selected area hierarchically..."));
433 			abortseq = getinterruptkey();
434 			if (abortseq != 0)
435 				formatinfstr(infstr, _(" (type %s to abort)"), abortseq);
436 			ttyputmsg(returninfstr(infstr));
437 			(void)drcb_check(np, TRUE, TRUE);
438 			return;
439 		}
440 		if (namesamen(pp, x_("just-1-error"), l) == 0)
441 		{
442 			(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
443 				options | DRCFIRSTERROR, VINTEGER);
444 			ttyputmsg(M_("Hierarchical DRC will stop after first error in a cell"));
445 			return;
446 		}
447 		if (namesamen(pp, x_("all-errors"), l) == 0)
448 		{
449 			(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
450 				options & ~DRCFIRSTERROR, VINTEGER);
451 			ttyputmsg(M_("Hierarchical DRC will find all errors in a cell"));
452 			return;
453 		}
454 		if (namesamen(pp, x_("reset-check-dates"), l) == 0)
455 		{
456 			dr_reset_dates();
457 			ttyputmsg(M_("All date information about valid DRC is reset"));
458 			return;
459 		}
460 		ttyputbadusage(x_("telltool drc batch"));
461 		return;
462 	}
463 
464 	if (namesamen(pp, x_("quick-check"), l) == 0 && l >= 7)
465 	{
466 		/* get the current cell */
467 		np = getcurcell();
468 		if (np == NONODEPROTO)
469 		{
470 			ttyputerr(_("No current cell"));
471 			return;
472 		}
473 		dr_checkentirecell(np, 0, 0, 0, FALSE);
474 		return;
475 	}
476 
477 	if (namesamen(pp, x_("quick-select-check"), l) == 0 && l >= 7)
478 	{
479 		/* get the current cell */
480 		np = getcurcell();
481 		if (np == NONODEPROTO)
482 		{
483 			ttyputerr(_("No current cell"));
484 			return;
485 		}
486 		dr_checkentirecell(np, 0, 0, 0, TRUE);
487 		return;
488 	}
489 
490 	if (namesamen(pp, x_("shortcheck"), l) == 0)
491 	{
492 		if (count < 2)
493 		{
494 			ttyputusage(x_("telltool drc shortcheck (run|ignore|unignore)"));
495 			return;
496 		}
497 		l = estrlen(pp = par[1]);
498 		if (namesamen(pp, x_("run"), l) == 0)
499 		{
500 			/* make sure network tool is on */
501 			if ((net_tool->toolstate&TOOLON) == 0)
502 			{
503 				ttyputerr(M_("Network tool must be running...turning it on"));
504 				toolturnon(net_tool);
505 				ttyputerr(M_("...now reissue the DRC command"));
506 				return;
507 			}
508 			dr_flatwrite(getcurcell());
509 			return;
510 		}
511 		if (namesamen(pp, x_("ignore"), l) == 0)
512 		{
513 			if (count < 3)
514 			{
515 				ttyputusage(x_("telltool drc shortcheck ignore CELL"));
516 				return;
517 			}
518 			dr_flatignore(par[2]);
519 			return;
520 		}
521 		if (namesamen(pp, x_("unignore"), l) == 0)
522 		{
523 			if (count < 3)
524 			{
525 				ttyputusage(x_("telltool drc shortcheck unignore CELL"));
526 				return;
527 			}
528 			dr_flatunignore(par[2]);
529 			return;
530 		}
531 		ttyputbadusage(x_("telltool drc shortcheck"));
532 		return;
533 	}
534 
535 	if (namesamen(pp, x_("verbose"), l) == 0)
536 	{
537 		if (!negate)
538 		{
539 			(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_verbosekey, 1, VINTEGER|VDONTSAVE);
540 			ttyputverbose(M_("DRC verbose"));
541 		} else
542 		{
543 			if (getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_verbosekey) != NOVARIABLE)
544 				(void)delvalkey((INTBIG)dr_tool, VTOOL, dr_verbosekey);
545 			ttyputverbose(M_("DRC brief"));
546 		}
547 		return;
548 	}
549 
550 	if (namesamen(pp, x_("reasonable"), l) == 0)
551 	{
552 		if (!negate)
553 		{
554 			(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
555 				options | DRCREASONABLE, VINTEGER);
556 			ttyputverbose(M_("DRC will consider only reasonable number of polygons"));
557 		} else
558 		{
559 			(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
560 				options & ~DRCREASONABLE, VINTEGER);
561 			ttyputverbose(M_("DRC will consider all polygons"));
562 		}
563 		return;
564 	}
565 	ttyputbadusage(x_("telltool drc"));
566 }
567 
568 /*
569  * make request of the DRC tool:
570  * "check-instances" TAKES: CELL, COUNT, NODEINST array, BOOLEAN validity-array
571  */
dr_request(CHAR * command,va_list ap)572 INTBIG dr_request(CHAR *command, va_list ap)
573 {
574 	REGISTER NODEPROTO *cell;
575 	REGISTER NODEINST **nodelist;
576 	REGISTER BOOLEAN *validity;
577 	REGISTER INTBIG arg1, arg2, arg3, arg4, count;
578 
579 	if (namesame(command, x_("check-instances")) == 0)
580 	{
581 		/* get the arguments */
582 		arg1 = va_arg(ap, INTBIG);
583 		arg2 = va_arg(ap, INTBIG);
584 		arg3 = va_arg(ap, INTBIG);
585 		arg4 = va_arg(ap, INTBIG);
586 
587 		cell = (NODEPROTO *)arg1;
588 		count = arg2;
589 		nodelist = (NODEINST **)arg3;
590 		validity = (BOOLEAN *)arg4;
591 		dr_checkentirecell(cell, count, nodelist, validity, FALSE);
592 		return(0);
593 	}
594 	return(0);
595 }
596 
dr_examinenodeproto(NODEPROTO * np)597 void dr_examinenodeproto(NODEPROTO *np)
598 {
599 	REGISTER INTBIG i, errs;
600 	REGISTER CHAR *pt;
601 	if (dr_examinecell(np, FALSE) != 0)
602 	{
603 		errs = numerrors();
604 		for(i=0; i<errs; i++)
605 		{
606 			pt = reportnexterror(0, 0, 0);
607 			ttyputmsg(x_("%s"), pt);
608 		}
609 
610 		/* reset error pointers to start of list */
611 		termerrorlogging(FALSE);
612 	}
613 }
614 
615 /*
616  * Routine to examine cell "np" nonhierarchically and return the number of errors found.
617  */
dr_examinecell(NODEPROTO * np,BOOLEAN report)618 INTBIG dr_examinecell(NODEPROTO *np, BOOLEAN report)
619 {
620 	REGISTER NODEINST *ni;
621 	REGISTER ARCINST *ai;
622 	REGISTER INTBIG errorcount;
623 
624 	if (stopping(STOPREASONDRC)) return(0);
625 
626 	/* do not check things in hidden libraries (such as the clipboard) */
627 	if ((np->lib->userbits&HIDDENLIBRARY) != 0) return(0);
628 
629 	/* make sure network tool is on */
630 	if ((net_tool->toolstate&TOOLON) == 0) return(0);
631 
632 	/* handle schematics separately */
633 	if (np->cellview == el_schematicview || np->tech == sch_tech)
634 	{
635 		dr_checkschematiccell(np, TRUE);
636 		return(0);
637 	}
638 
639 	/* clear errors */
640 	initerrorlogging(_("DRC"));
641 
642 	drcb_initincrementalcheck(np);
643 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
644 		(void)drcb_checkincremental(ni->geom, TRUE);
645 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
646 		(void)drcb_checkincremental(ai->geom, TRUE);
647 	errorcount = numerrors();
648 	if (report)
649 		ttyputmsg(_("Cell %s checked at this level only (%ld errors)"),
650 			describenodeproto(np), errorcount);
651 	termerrorlogging(TRUE);
652 	return(errorcount);
653 }
654 
dr_slice(void)655 void dr_slice(void)
656 {
657 	REGISTER DCHECK *d, *nextd;
658 	REGISTER NODEPROTO *np;
659 	REGISTER BOOLEAN didcheck;
660 	REGISTER VARIABLE *var;
661 
662 	/* see if the tool should be off */
663 	var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_incrementalonkey);
664 	if (var != NOVARIABLE && var->addr == 0)
665 	{
666 		toolturnoff(dr_tool, FALSE);
667 		return;
668 	}
669 
670 	if (dr_firstdcheck == NODCHECK) return;
671 
672 	/* make sure network tool is on */
673 	if ((net_tool->toolstate&TOOLON) == 0)
674 	{
675 		ttyputerr(M_("Network tool must be running...turning it on"));
676 		toolturnon(net_tool);
677 		return;
678 	}
679 
680 	/* mark this activity */
681 	setactivity(_("DRC"));
682 
683 	/* first clear the ignore information on any objects that changed */
684 	for(d = dr_firstdcheck; d != NODCHECK; d = d->nextdcheck)
685 	{
686 		if (d->entrytype == NODEMOD || d->entrytype == NODEKILL)
687 			dr_unignore(d->cell, TRUE, d->entryaddr);
688 		if (d->entrytype == ARCMOD || d->entrytype == ARCKILL)
689 			dr_unignore(d->cell, FALSE, d->entryaddr);
690 	}
691 
692 	/* clear errors */
693 	dr_logerrors = FALSE;
694 
695 	np = NONODEPROTO;
696 	didcheck = FALSE;
697 	for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
698 	{
699 		nextd = d->nextdcheck;
700 		if (!stopping(STOPREASONDRC))
701 		{
702 			if (d->entrytype == NODEMOD || d->entrytype == NODENEW)
703 			{
704 				NODEINST *ni;
705 
706 				ni = (NODEINST *)d->entryaddr;
707 				if ((ni->userbits&DEADN) == 0)
708 				{
709 					if (d->cell != np)
710 					{
711 						np = ni->parent;
712 						drcb_initincrementalcheck(np);
713 						didcheck = TRUE;
714 					}
715 					(void)drcb_checkincremental(ni->geom, FALSE);
716 				}
717 			}
718 			if (d->entrytype == ARCMOD || d->entrytype == ARCNEW)
719 			{
720 				ARCINST *ai;
721 
722 				ai = (ARCINST *)d->entryaddr;
723 				if ((ai->userbits&DEADA) == 0)
724 				{
725 					if (d->cell != np)
726 					{
727 						np = ai->parent;
728 						drcb_initincrementalcheck(np);
729 						didcheck = TRUE;
730 					}
731 					(void)drcb_checkincremental(ai->geom, FALSE);
732 				}
733 			}
734 		}
735 		dr_freedcheck(d);
736 	}
737 	dr_firstdcheck = NODCHECK;
738 	dr_logerrors = TRUE;
739 }
740 
741 /******************** DATABASE CHANGES ********************/
742 
dr_modifynodeinst(NODEINST * ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,INTBIG oldrot,INTBIG oldtran)743 void dr_modifynodeinst(NODEINST *ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,
744 	INTBIG oldrot,INTBIG oldtran)
745 {
746 	dr_queuecheck(ni, ni->parent, NODEMOD);
747 }
748 
dr_modifyarcinst(ARCINST * ai,INTBIG oldxA,INTBIG oldyA,INTBIG oldxB,INTBIG oldyB,INTBIG oldwid,INTBIG oldlen)749 void dr_modifyarcinst(ARCINST *ai,INTBIG oldxA, INTBIG oldyA, INTBIG oldxB, INTBIG oldyB,
750 	INTBIG oldwid, INTBIG oldlen)
751 {
752 	dr_queuecheck(ai, ai->parent, ARCMOD);
753 }
754 
dr_newobject(INTBIG addr,INTBIG type)755 void dr_newobject(INTBIG addr, INTBIG type)
756 {
757 	REGISTER NODEINST *ni;
758 	REGISTER ARCINST *ai;
759 
760 	if ((type&VTYPE) == VNODEINST)
761 	{
762 		ni = (NODEINST *)addr;
763 		dr_queuecheck(ni, ni->parent, NODENEW);
764 	} else if ((type&VTYPE) == VARCINST)
765 	{
766 		ai = (ARCINST *)addr;
767 		dr_queuecheck(ai, ai->parent, ARCNEW);
768 	}
769 }
770 
dr_killobject(INTBIG addr,INTBIG type)771 void dr_killobject(INTBIG addr, INTBIG type)
772 {
773 	REGISTER DCHECK *d, *lastd, *nextd;
774 	REGISTER NODEINST *ni;
775 	REGISTER ARCINST *ai;
776 
777 	/* remove any others in the list that point to this deleted object */
778 	lastd = NODCHECK;
779 	for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
780 	{
781 		nextd = d->nextdcheck;
782 		if (d->entryaddr == (void *)addr)
783 		{
784 			if (lastd == NODCHECK) dr_firstdcheck = nextd; else
785 				lastd->nextdcheck = nextd;
786 			dr_freedcheck(d);
787 			continue;
788 		}
789 		lastd = d;
790 	}
791 
792 	if ((type&VTYPE) == VNODEINST)
793 	{
794 		ni = (NODEINST *)addr;
795 		dr_queuecheck(ni, ni->parent, NODEKILL);
796 	} else if ((type&VTYPE) == VARCINST)
797 	{
798 		ai = (ARCINST *)addr;
799 		dr_queuecheck(ai, ai->parent, ARCKILL);
800 	}
801 }
802 
dr_eraselibrary(LIBRARY * lib)803 void dr_eraselibrary(LIBRARY *lib)
804 {
805 	dr_unqueuecheck(lib);
806 }
807 
dr_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)808 void dr_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
809 {
810 	if (type == VTECHNOLOGY)
811 	{
812 		if (key == el_techstate_key)
813 		{
814 			/* code cannot be called by multiple procesors: uses globals */
815 			NOT_REENTRANT;
816 
817 			dr_curtech = NOTECHNOLOGY;
818 		}
819 	}
820 }
821 
822 /******************** SUPPORT ROUTINES ********************/
823 
824 /*
825  * routine to allocate a new dcheck module from the pool (if any) or memory
826  */
dr_allocdcheck(void)827 DCHECK *dr_allocdcheck(void)
828 {
829 	REGISTER DCHECK *d;
830 
831 	if (dr_dcheckfree == NODCHECK)
832 	{
833 		d = (DCHECK *)emalloc(sizeof (DCHECK), dr_tool->cluster);
834 		if (d == 0) return(NODCHECK);
835 	} else
836 	{
837 		/* take module from free list */
838 		d = dr_dcheckfree;
839 		dr_dcheckfree = (DCHECK *)d->nextdcheck;
840 	}
841 	return(d);
842 }
843 
844 /*
845  * routine to return dcheck module "d" to the pool of free modules
846  */
dr_freedcheck(DCHECK * d)847 void dr_freedcheck(DCHECK *d)
848 {
849 	d->nextdcheck = dr_dcheckfree;
850 	dr_dcheckfree = d;
851 }
852 
dr_queuecheck(void * addr,NODEPROTO * cell,INTBIG function)853 void dr_queuecheck(void *addr, NODEPROTO *cell, INTBIG function)
854 {
855 	REGISTER DCHECK *d;
856 
857 	/* do not examine anything in a hidden library (such as the clipboard) */
858 	if ((cell->lib->userbits&HIDDENLIBRARY) != 0) return;
859 
860 	d = dr_allocdcheck();
861 	if (d == NODCHECK)
862 	{
863 		ttyputnomemory();
864 		return;
865 	}
866 	d->entrytype = function;
867 	d->cell = cell;
868 	d->entryaddr = addr;
869 	d->nextdcheck = dr_firstdcheck;
870 	dr_firstdcheck = d;
871 }
872 
873 /*
874  * Routine to remove all check objects that are in library "lib"
875  * (because the library has been deleted)
876  */
dr_unqueuecheck(LIBRARY * lib)877 void dr_unqueuecheck(LIBRARY *lib)
878 {
879 	REGISTER DCHECK *d, *nextd, *lastd;
880 
881 	lastd = NODCHECK;
882 	for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
883 	{
884 		nextd = d->nextdcheck;
885 		if (d->cell == NONODEPROTO || d->cell->lib == lib)
886 		{
887 			if (lastd == NODCHECK) dr_firstdcheck = nextd; else
888 				lastd->nextdcheck = nextd;
889 			dr_freedcheck(d);
890 			continue;
891 		}
892 		lastd = d;
893 	}
894 }
895 
896 /*
897  * routine to delete DRC ignore information on object "pos"
898  */
dr_unignore(NODEPROTO * np,BOOLEAN objisnode,void * addr)899 void dr_unignore(NODEPROTO *np, BOOLEAN objisnode, void *addr)
900 {
901 	REGISTER GEOM **ignorelist, *p1, *p2, *geom;
902 	REGISTER VARIABLE *var;
903 	REGISTER INTBIG i, len, pt;
904 
905 	var = getvalkey((INTBIG)np, VNODEPROTO, VGEOM|VISARRAY, dr_ignore_listkey);
906 
907 	/* if the list is empty there is nothing to do */
908 	if (var == NOVARIABLE) return;
909 
910 	/* see if this entry is mentioned in the list */
911 	len = getlength(var);
912 	for(i=0; i<len; i++)
913 	{
914 		geom = ((GEOM **)var->addr)[i];
915 		if (geom->entryisnode == objisnode && geom->entryaddr.blind == addr) break;
916 	}
917 	if (i >= len) return;
918 
919 	/* create a new list without the entry */
920 	ignorelist = (GEOM **)emalloc((len * (sizeof (GEOM *))), el_tempcluster);
921 	if (ignorelist == 0)
922 	{
923 		ttyputnomemory();
924 		return;
925 	}
926 
927 	/* search list and remove entries that mention this module */
928 	pt = 0;
929 	for(i=0; i<len; i += 2)
930 	{
931 		p1 = ((GEOM **)var->addr)[i];
932 		p2 = ((GEOM **)var->addr)[i+1];
933 		if (p1->entryisnode == objisnode && p1->entryaddr.blind == addr) continue;
934 		if (p2->entryisnode == objisnode && p2->entryaddr.blind == addr) continue;
935 		ignorelist[pt++] = p1;   ignorelist[pt++] = p2;
936 	}
937 
938 	/* set the list back in place */
939 	if (pt > 0) (void)setvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey,
940 		(INTBIG)ignorelist, (INTBIG)(VGEOM|VISARRAY|(pt<<VLENGTHSH)|VDONTSAVE)); else
941 			(void)delvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey);
942 	efree((CHAR *)ignorelist);
943 }
944 
945 /*
946  * routine to determine the node prototype specified in "name" (given that
947  * there were "count" parameters to the command and that "name" should be in
948  * the second).  Returns NONODEPROTO if there is an error.
949  */
dr_checkthiscell(INTBIG count,CHAR * name)950 NODEPROTO *dr_checkthiscell(INTBIG count, CHAR *name)
951 {
952 	REGISTER NODEPROTO *np;
953 
954 	if (count < 2)
955 	{
956 		np = getcurcell();
957 		if (np == NONODEPROTO) ttyputerr(_("No current cell"));
958 		return(np);
959 	}
960 	np = getnodeproto(name);
961 	if (np == NONODEPROTO)
962 	{
963 		ttyputerr(_("No cell named %s"), name);
964 		return(NONODEPROTO);
965 	}
966 	if (np->primindex != 0)
967 	{
968 		ttyputerr(_("Can only check cells, not primitives"));
969 		return(NONODEPROTO);
970 	}
971 	return(np);
972 }
973 
974 /*
975  * Routine to obtain the current value of the DRC options.
976  * Note that this cannot be automatically maintained by the "newvariable()" hook
977  * because the DRC isn't always on.
978  */
dr_getoptionsvalue(void)979 INTBIG dr_getoptionsvalue(void)
980 {
981 	REGISTER VARIABLE *var;
982 
983 	var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_optionskey);
984 	if (var == NOVARIABLE) return(0);
985 	return(var->addr);
986 }
987 
988 /*
989  * Turns off all saved date information about valid DRC.
990  */
dr_reset_dates(void)991 void dr_reset_dates(void)
992 {
993 	REGISTER LIBRARY *lib;
994 	REGISTER NODEPROTO *np;
995 	REGISTER VARIABLE *var;
996 
997 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
998 	{
999 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1000 		{
1001 			var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, dr_lastgooddrckey);
1002 			if (var == NOVARIABLE) continue;
1003 			nextchangequiet();
1004 			(void)delvalkey((INTBIG)np, VNODEPROTO, dr_lastgooddrckey);
1005 		}
1006 	}
1007 }
1008 
1009 /*
1010  * Routine to check all of cell "cell".  Returns number of errors found.
1011  */
dr_checkentirecell(NODEPROTO * cell,INTBIG count,NODEINST ** nodestocheck,BOOLEAN * validity,BOOLEAN justarea)1012 void dr_checkentirecell(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck, BOOLEAN *validity,
1013 	BOOLEAN justarea)
1014 {
1015 	REGISTER LIBRARY *lib;
1016 	REGISTER NODEPROTO *np;
1017 	REGISTER INTBIG errorcount;
1018 
1019 	if (cell->cellview == el_schematicview || cell->tech == sch_tech)
1020 	{
1021 		/* hierarchical check of schematics */
1022 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1023 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1024 				np->temp1 = 0;
1025 		initerrorlogging(_("Schematic DRC"));
1026 		dr_checkschematiccellrecursively(cell);
1027 		errorcount = numerrors();
1028 		if (errorcount != 0) ttyputmsg(_("TOTAL OF %ld ERRORS FOUND"), errorcount);
1029 		termerrorlogging(TRUE);
1030 		return;
1031 	}
1032 	dr_quickcheck(cell, count, nodestocheck, validity, justarea);
1033 }
1034 
1035 /****************************** SCHEMATIC DRC ******************************/
1036 
dr_checkschematiccellrecursively(NODEPROTO * cell)1037 void dr_checkschematiccellrecursively(NODEPROTO *cell)
1038 {
1039 	REGISTER NODEINST *ni;
1040 	REGISTER NODEPROTO *cnp;
1041 
1042 	cell->temp1 = 1;
1043 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1044 	{
1045 		if (ni->proto->primindex != 0) continue;
1046 		cnp = contentsview(ni->proto);
1047 		if (cnp == NONODEPROTO) cnp = ni->proto;
1048 		if (cnp->temp1 != 0) continue;
1049 
1050 		/* ignore documentation icon */
1051 		if (isiconof(ni->proto, cell)) continue;
1052 
1053 		dr_checkschematiccellrecursively(cnp);
1054 	}
1055 
1056 	/* now check this cell */
1057 	ttyputmsg(_("Checking schematic cell %s"), describenodeproto(cell));
1058 	dr_checkschematiccell(cell, FALSE);
1059 }
1060 
dr_checkschematiccell(NODEPROTO * cell,BOOLEAN justthis)1061 void dr_checkschematiccell(NODEPROTO *cell, BOOLEAN justthis)
1062 {
1063 	REGISTER NODEINST *ni;
1064 	REGISTER ARCINST *ai;
1065 	REGISTER INTBIG errorcount, initialerrorcount, thiserrors;
1066 	REGISTER CHAR *indent;
1067 
1068 	if (justthis) initerrorlogging(_("Schematic DRC"));
1069 	initialerrorcount = numerrors();
1070 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1071 		dr_schdocheck(ni->geom);
1072 	for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1073 		dr_schdocheck(ai->geom);
1074 	errorcount = numerrors();
1075 	thiserrors = errorcount - initialerrorcount;
1076 	if (justthis) indent = x_(""); else
1077 		indent = x_("   ");
1078 	if (thiserrors == 0) ttyputmsg(_("%sNo errors found"), indent); else
1079 		ttyputmsg(_("%s%ld errors found"), indent, thiserrors);
1080 	if (justthis) termerrorlogging(TRUE);
1081 }
1082 
1083 /*
1084  * Routine to check schematic object "geom".
1085  */
dr_schdocheck(GEOM * geom)1086 void dr_schdocheck(GEOM *geom)
1087 {
1088 	REGISTER NODEPROTO *cell, *np;
1089 	REGISTER NODEINST *ni;
1090 	REGISTER ARCINST *ai;
1091 	ARCINST **thearcs;
1092 	REGISTER PORTARCINST *pi;
1093 	REGISTER PORTPROTO *pp;
1094 	REGISTER VARIABLE *var, *fvar;
1095 	REGISTER BOOLEAN checkdangle;
1096 	REGISTER INTBIG i, j, fun, signals, portwidth, nodesize;
1097 	INTBIG x, y;
1098 	void *err, *infstr;
1099 	UINTBIG descript[TEXTDESCRIPTSIZE];
1100 
1101 	cell = geomparent(geom);
1102 	if (geom->entryisnode)
1103 	{
1104 		ni = geom->entryaddr.ni;
1105 
1106 		/* check for bus pins that don't connect to any bus arcs */
1107 		if (ni->proto == sch_buspinprim)
1108 		{
1109 			/* proceed only if it has no exports on it */
1110 			if (ni->firstportexpinst == NOPORTEXPINST)
1111 			{
1112 				/* must not connect to any bus arcs */
1113 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1114 					if (pi->conarcinst->proto == sch_busarc) break;
1115 				if (pi == NOPORTARCINST)
1116 				{
1117 					err = logerror(_("Bus pin does not connect to any bus arcs"), cell, 0);
1118 					addgeomtoerror(err, geom, TRUE, 0, 0);
1119 					return;
1120 				}
1121 			}
1122 
1123 			/* flag bus pin if more than 1 wire is connected */
1124 			i = 0;
1125 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1126 				if (pi->conarcinst->proto == sch_wirearc) i++;
1127 			if (i > 1)
1128 			{
1129 				err = logerror(_("Wire arcs cannot connect through a bus pin"), cell, 0);
1130 				addgeomtoerror(err, geom, TRUE, 0, 0);
1131 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1132 					if (pi->conarcinst->proto == sch_wirearc)
1133 						addgeomtoerror(err, pi->conarcinst->geom, TRUE, 0, 0);
1134 				return;
1135 			}
1136 		}
1137 
1138 		/* check all pins */
1139 		if ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH == NPPIN)
1140 		{
1141 			/* may be stranded if there are no exports or arcs */
1142 			if (ni->firstportexpinst == NOPORTEXPINST && ni->firstportarcinst == NOPORTARCINST)
1143 			{
1144 				/* see if the pin has displayable variables on it */
1145 				for(i=0; i<ni->numvar; i++)
1146 				{
1147 					var = &ni->firstvar[i];
1148 					if ((var->type&VDISPLAY) != 0) break;
1149 				}
1150 				if (i >= ni->numvar)
1151 				{
1152 					err = logerror(_("Stranded pin (not connected or exported)"), cell, 0);
1153 					addgeomtoerror(err, geom, TRUE, 0, 0);
1154 					return;
1155 				}
1156 			}
1157 
1158 			if (isinlinepin(ni, &thearcs))
1159 			{
1160 				err = logerror(_("Unnecessary pin (between 2 arcs)"), cell, 0);
1161 				addgeomtoerror(err, geom, TRUE, 0, 0);
1162 				return;
1163 			}
1164 
1165 			if (invisiblepinwithoffsettext(ni, &x, &y, FALSE))
1166 			{
1167 				err = logerror(_("Invisible pin has text in different location"), cell, 0);
1168 				addgeomtoerror(err, geom, TRUE, 0, 0);
1169 				addlinetoerror(err, (ni->lowx+ni->highx)/2, (ni->lowy+ni->highy)/2, x, y);
1170 				return;
1171 			}
1172 		}
1173 
1174 		/* check parameters */
1175 		if (ni->proto->primindex == 0)
1176 		{
1177 			np = contentsview(ni->proto);
1178 			if (np == NONODEPROTO) np = ni->proto;
1179 
1180 			/* ensure that this node matches the parameter list */
1181 			for(i=0; i<ni->numvar; i++)
1182 			{
1183 				var = &ni->firstvar[i];
1184 				if (TDGETISPARAM(var->textdescript) == 0) continue;
1185 				fvar = NOVARIABLE;
1186 				for(j=0; j<np->numvar; j++)
1187 				{
1188 					fvar = &np->firstvar[j];
1189 					if (TDGETISPARAM(fvar->textdescript) == 0) continue;
1190 					if (namesame(makename(var->key), makename(fvar->key)) == 0) break;
1191 				}
1192 				if (j >= np->numvar)
1193 				{
1194 					/* this node's parameter is no longer on the cell: delete from instance */
1195 					infstr = initinfstr();
1196 					formatinfstr(infstr, _("Parameter '%s' on node %s is invalid and has been deleted"),
1197 						truevariablename(var), describenodeinst(ni));
1198 					err = logerror(returninfstr(infstr), cell, 0);
1199 					addgeomtoerror(err, geom, TRUE, 0, 0);
1200 					startobjectchange((INTBIG)ni, VNODEINST);
1201 					(void)delvalkey((INTBIG)ni, VNODEINST, var->key);
1202 					endobjectchange((INTBIG)ni, VNODEINST);
1203 					i--;
1204 				} else
1205 				{
1206 					/* this node's parameter is still on the cell: make sure units are OK */
1207 					if (TDGETUNITS(var->textdescript) != TDGETUNITS(fvar->textdescript))
1208 					{
1209 						infstr = initinfstr();
1210 						formatinfstr(infstr, _("Parameter '%s' on node %s had incorrect units (now fixed)"),
1211 							truevariablename(var), describenodeinst(ni));
1212 						err = logerror(returninfstr(infstr), cell, 0);
1213 						addgeomtoerror(err, geom, TRUE, 0, 0);
1214 						startobjectchange((INTBIG)ni, VNODEINST);
1215 						TDCOPY(descript, var->textdescript);
1216 						TDSETUNITS(descript, TDGETUNITS(fvar->textdescript));
1217 						modifydescript((INTBIG)ni, VNODEINST, var, descript);
1218 						endobjectchange((INTBIG)ni, VNODEINST);
1219 					}
1220 
1221 					/* make sure visibility is OK */
1222 					if (TDGETINTERIOR(fvar->textdescript) != 0)
1223 					{
1224 						if ((var->type&VDISPLAY) != 0)
1225 						{
1226 							infstr = initinfstr();
1227 							formatinfstr(infstr, _("Parameter '%s' on node %s should not be visible (now fixed)"),
1228 								truevariablename(var), describenodeinst(ni));
1229 							err = logerror(returninfstr(infstr), cell, 0);
1230 							addgeomtoerror(err, geom, TRUE, 0, 0);
1231 							startobjectchange((INTBIG)ni, VNODEINST);
1232 							var->type &= ~VDISPLAY;
1233 							endobjectchange((INTBIG)ni, VNODEINST);
1234 						}
1235 					} else
1236 					{
1237 						if ((var->type&VDISPLAY) == 0)
1238 						{
1239 							infstr = initinfstr();
1240 							formatinfstr(infstr, _("Parameter '%s' on node %s should be visible (now fixed)"),
1241 								truevariablename(var), describenodeinst(ni));
1242 							err = logerror(returninfstr(infstr), cell, 0);
1243 							addgeomtoerror(err, geom, TRUE, 0, 0);
1244 							startobjectchange((INTBIG)ni, VNODEINST);
1245 							var->type |= VDISPLAY;
1246 							endobjectchange((INTBIG)ni, VNODEINST);
1247 						}
1248 					}
1249 				}
1250 			}
1251 		}
1252 	} else
1253 	{
1254 		ai = geom->entryaddr.ai;
1255 
1256 		/* check for being floating if it does not have a visible name on it */
1257 		var = getvalkey((INTBIG)ai, VARCINST, -1, el_arc_name_key);
1258 		if (var == NOVARIABLE || (var->type&VDISPLAY) == 0) checkdangle = TRUE; else
1259 			checkdangle = FALSE;
1260 		if (checkdangle)
1261 		{
1262 			/* do not check for dangle when busses are on named networks */
1263 			if (ai->proto == sch_busarc)
1264 			{
1265 				if (ai->network->namecount > 0 && ai->network->tempname == 0) checkdangle = FALSE;
1266 			}
1267 		}
1268 		if (checkdangle)
1269 		{
1270 			/* check to see if this arc is floating */
1271 			for(i=0; i<2; i++)
1272 			{
1273 				ni = ai->end[i].nodeinst;
1274 
1275 				/* OK if not a pin */
1276 				fun = nodefunction(ni);
1277 				if (fun != NPPIN) continue;
1278 
1279 				/* OK if it has exports on it */
1280 				if (ni->firstportexpinst != NOPORTEXPINST) continue;
1281 
1282 				/* OK if it connects to more than 1 arc */
1283 				if (ni->firstportarcinst == NOPORTARCINST) continue;
1284 				if (ni->firstportarcinst->nextportarcinst != NOPORTARCINST) continue;
1285 
1286 				/* the arc dangles */
1287 				err = logerror(_("Arc dangles"), cell, 0);
1288 				addgeomtoerror(err, geom, TRUE, 0, 0);
1289 				return;
1290 			}
1291 		}
1292 
1293 
1294 		/* check to see if its width is sensible */
1295 		if (ai->network == NONETWORK) signals = 1; else
1296 		{
1297 			signals = ai->network->buswidth;
1298 			if (signals < 1) signals = 1;
1299 		}
1300 		for(i=0; i<2; i++)
1301 		{
1302 			ni = ai->end[i].nodeinst;
1303 			if (ni->proto->primindex != 0) continue;
1304 			np = contentsview(ni->proto);
1305 			if (np == NONODEPROTO) np = ni->proto;
1306 			pp = equivalentport(ni->proto, ai->end[i].portarcinst->proto, np);
1307 			if (pp == NOPORTPROTO)
1308 			{
1309 				infstr = initinfstr();
1310 				formatinfstr(infstr, _("Arc %s connects to port %s of node %s, but there is no equivalent port in cell %s"),
1311 					describearcinst(ai), ai->end[i].portarcinst->proto->protoname, describenodeinst(ni), describenodeproto(np));
1312 				err = logerror(returninfstr(infstr), cell, 0);
1313 				addgeomtoerror(err, geom, TRUE, 0, 0);
1314 				addgeomtoerror(err, ni->geom, TRUE, 0, 0);
1315 				continue;
1316 			}
1317 			portwidth = pp->network->buswidth;
1318 			if (portwidth < 1) portwidth = 1;
1319 			nodesize = ni->arraysize;
1320 			if (nodesize <= 0) nodesize = 1;
1321 			if (signals != portwidth && signals != portwidth*nodesize)
1322 			{
1323 				infstr = initinfstr();
1324 				formatinfstr(infstr, _("Arc %s (%ld wide) connects to port %s of node %s (%ld wide)"),
1325 					describearcinst(ai), signals, pp->protoname, describenodeinst(ni), portwidth);
1326 				err = logerror(returninfstr(infstr), cell, 0);
1327 				addgeomtoerror(err, geom, TRUE, 0, 0);
1328 				addgeomtoerror(err, ni->geom, TRUE, 0, 0);
1329 			}
1330 		}
1331 	}
1332 
1333 	/* check for overlap */
1334 	dr_schcheckobjectvicinity(geom, geom, el_matid);
1335 }
1336 
1337 /*
1338  * Routine to check whether object "geom" has a DRC violation with a neighboring object.
1339  */
dr_schcheckobjectvicinity(GEOM * topgeom,GEOM * geom,XARRAY trans)1340 void dr_schcheckobjectvicinity(GEOM *topgeom, GEOM *geom, XARRAY trans)
1341 {
1342 	REGISTER INTBIG i, total;
1343 	REGISTER NODEINST *ni, *subni;
1344 	REGISTER ARCINST *ai, *subai;
1345 	XARRAY xformr, xformt, subrot, localtrans;
1346 	static POLYGON *poly = NOPOLYGON;
1347 
1348 	needstaticpolygon(&poly, 4, dr_tool->cluster);
1349 	if (geom->entryisnode)
1350 	{
1351 		ni = geom->entryaddr.ni;
1352 		makerot(ni, xformr);
1353 		transmult(xformr, trans, localtrans);
1354 		if (ni->proto->primindex == 0)
1355 		{
1356 			if ((ni->userbits&NEXPAND) != 0)
1357 			{
1358 				/* expand the instance */
1359 				maketrans(ni, xformt);
1360 				transmult(xformt, localtrans, subrot);
1361 				for(subni = ni->proto->firstnodeinst; subni != NONODEINST; subni = subni->nextnodeinst)
1362 					dr_schcheckobjectvicinity(topgeom, subni->geom, subrot);
1363 				for(subai = ni->proto->firstarcinst; subai != NOARCINST; subai = subai->nextarcinst)
1364 					dr_schcheckobjectvicinity(topgeom, subai->geom, subrot);
1365 			}
1366 		} else
1367 		{
1368 			/* primitive */
1369 			total = nodepolys(ni, 0, NOWINDOWPART);
1370 			for(i=0; i<total; i++)
1371 			{
1372 				shapenodepoly(ni, i, poly);
1373 				xformpoly(poly, localtrans);
1374 				(void)dr_schcheckpolygonvicinity(topgeom, poly);
1375 			}
1376 		}
1377 	} else
1378 	{
1379 		ai = geom->entryaddr.ai;
1380 		total = arcpolys(ai, NOWINDOWPART);
1381 		for(i=0; i<total; i++)
1382 		{
1383 			shapearcpoly(ai, i, poly);
1384 			xformpoly(poly, trans);
1385 			(void)dr_schcheckpolygonvicinity(topgeom, poly);
1386 		}
1387 	}
1388 }
1389 
1390 /*
1391  * Routine to check whether polygon "poly" from object "geom" has a DRC violation
1392  * with a neighboring object.  Returns TRUE if an error was found.
1393  */
dr_schcheckpolygonvicinity(GEOM * geom,POLYGON * poly)1394 BOOLEAN dr_schcheckpolygonvicinity(GEOM *geom, POLYGON *poly)
1395 {
1396 	REGISTER NODEINST *ni, *oni;
1397 	REGISTER ARCINST *ai, *oai;
1398 	REGISTER NODEPROTO *cell;
1399 	REGISTER GEOM *ogeom;
1400 	REGISTER PORTARCINST *pi;
1401 	REGISTER NETWORK *net;
1402 	REGISTER BOOLEAN connected;
1403 	REGISTER INTBIG i, sea;
1404 
1405 	/* don't check text */
1406 	if (poly->style == TEXTCENT || poly->style == TEXTTOP ||
1407 		poly->style == TEXTBOT || poly->style == TEXTLEFT ||
1408 		poly->style == TEXTRIGHT || poly->style == TEXTTOPLEFT ||
1409 		poly->style == TEXTBOTLEFT || poly->style == TEXTTOPRIGHT ||
1410 		poly->style == TEXTBOTRIGHT || poly->style == TEXTBOX ||
1411 		poly->style == GRIDDOTS) return(FALSE);
1412 
1413 	cell = geomparent(geom);
1414 	if (geom->entryisnode) ni = geom->entryaddr.ni; else ai = geom->entryaddr.ai;
1415 	sea = initsearch(geom->lowx, geom->highx, geom->lowy, geom->highy, cell);
1416 	for(;;)
1417 	{
1418 		ogeom = nextobject(sea);
1419 		if (ogeom == NOGEOM) break;
1420 
1421 		/* canonicalize so that errors are found only once */
1422 		if ((INTBIG)geom <= (INTBIG)ogeom) continue;
1423 
1424 		/* what type of object was found in area */
1425 		if (ogeom->entryisnode)
1426 		{
1427 			/* found node nearby */
1428 			oni = ogeom->entryaddr.ni;
1429 			if (geom->entryisnode)
1430 			{
1431 				/* this is node, nearby is node: see if two nodes touch */
1432 				for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1433 					net->temp1 = 0;
1434 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1435 					pi->conarcinst->network->temp1 |= 1;
1436 				for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1437 					pi->conarcinst->network->temp1 |= 2;
1438 				for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1439 					if (net->temp1 == 3) break;
1440 				if (net != NONETWORK) continue;
1441 			} else
1442 			{
1443 				/* this is arc, nearby is node: see if electrically connected */
1444 				for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1445 					if (pi->conarcinst->network == ai->network) break;
1446 				if (pi != NOPORTARCINST) continue;
1447 			}
1448 
1449 			/* no connection: check for touching another */
1450 			if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, FALSE))
1451 			{
1452 				termsearch(sea);
1453 				return(TRUE);
1454 			}
1455 		} else
1456 		{
1457 			/* found arc nearby */
1458 			oai = ogeom->entryaddr.ai;
1459 			if (geom->entryisnode)
1460 			{
1461 				/* this is node, nearby is arc: see if electrically connected */
1462 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1463 					if (pi->conarcinst->network == oai->network) break;
1464 				if (pi != NOPORTARCINST) continue;
1465 
1466 				if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, FALSE))
1467 				{
1468 					termsearch(sea);
1469 					return(TRUE);
1470 				}
1471 			} else
1472 			{
1473 				/* this is arc, nearby is arc: check for colinearity */
1474 				if (dr_schcheckcolinear(ai, oai))
1475 				{
1476 					termsearch(sea);
1477 					return(TRUE);
1478 				}
1479 
1480 				/* if not connected, check to see if they touch */
1481 				connected = FALSE;
1482 				if (ai->network == oai->network) connected = TRUE; else
1483 				{
1484 					if (ai->network->buswidth > 1 && oai->network->buswidth <= 1)
1485 					{
1486 						for(i=0; i<ai->network->buswidth; i++)
1487 							if (ai->network->networklist[i] == oai->network) break;
1488 						if (i < ai->network->buswidth) connected = TRUE;
1489 					} else if (oai->network->buswidth > 1 && ai->network->buswidth <= 1)
1490 					{
1491 						for(i=0; i<oai->network->buswidth; i++)
1492 							if (oai->network->networklist[i] == ai->network) break;
1493 						if (i < oai->network->buswidth) connected = TRUE;
1494 					}
1495 				}
1496 				if (!connected)
1497 				{
1498 					if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, TRUE))
1499 					{
1500 						termsearch(sea);
1501 						return(TRUE);
1502 					}
1503 				}
1504 			}
1505 		}
1506 	}
1507 	return(TRUE);
1508 }
1509 
1510 /*
1511  * Check polygon "poly" from object "geom" against
1512  * geom "ogeom" transformed by "otrans" (and really on top-level object "otopgeom").
1513  * Returns TRUE if an error was found.
1514  */
dr_schcheckpoly(GEOM * geom,POLYGON * poly,GEOM * otopgeom,GEOM * ogeom,XARRAY otrans,BOOLEAN cancross)1515 BOOLEAN dr_schcheckpoly(GEOM *geom, POLYGON *poly, GEOM *otopgeom, GEOM *ogeom, XARRAY otrans,
1516 	BOOLEAN cancross)
1517 {
1518 	REGISTER INTBIG i, total;
1519 	REGISTER NODEINST *ni, *subni;
1520 	REGISTER ARCINST *ai, *subai;
1521 	XARRAY xformr, xformt, thistrans, subrot;
1522 	static POLYGON *opoly = NOPOLYGON;
1523 
1524 	needstaticpolygon(&opoly, 4, dr_tool->cluster);
1525 	if (ogeom->entryisnode)
1526 	{
1527 		ni = ogeom->entryaddr.ni;
1528 		makerot(ni, xformr);
1529 		transmult(xformr, otrans, thistrans);
1530 		if (ni->proto->primindex == 0)
1531 		{
1532 			maketrans(ni, xformt);
1533 			transmult(xformt, thistrans, subrot);
1534 			for(subni = ni->proto->firstnodeinst; subni != NONODEINST; subni = subni->nextnodeinst)
1535 			{
1536 				if (dr_schcheckpoly(geom, poly, otopgeom, subni->geom, subrot, cancross))
1537 					return(TRUE);
1538 			}
1539 			for(subai = ni->proto->firstarcinst; subai != NOARCINST; subai = subai->nextarcinst)
1540 			{
1541 				if (dr_schcheckpoly(geom, poly, otopgeom, subai->geom, subrot, cancross))
1542 					return(TRUE);
1543 			}
1544 		} else
1545 		{
1546 			total = nodepolys(ni, 0, NOWINDOWPART);
1547 			for(i=0; i<total; i++)
1548 			{
1549 				shapenodepoly(ni, i, opoly);
1550 				xformpoly(opoly, thistrans);
1551 				if (dr_checkpolyagainstpoly(geom, poly, otopgeom, opoly, cancross))
1552 					return(TRUE);
1553 			}
1554 		}
1555 	} else
1556 	{
1557 		ai = ogeom->entryaddr.ai;
1558 		total = arcpolys(ai, NOWINDOWPART);
1559 		for(i=0; i<total; i++)
1560 		{
1561 			shapearcpoly(ai, i, opoly);
1562 			xformpoly(opoly, otrans);
1563 			if (dr_checkpolyagainstpoly(geom, poly, otopgeom, opoly, cancross))
1564 				return(TRUE);
1565 		}
1566 	}
1567 	return(FALSE);
1568 }
1569 
1570 /*
1571  * Check polygon "poly" from object "geom" against
1572  * polygon "opoly" from object "ogeom".
1573  * If "cancross" is TRUE, they can cross each other (but an endpoint cannot touch).
1574  * Returns TRUE if an error was found.
1575  */
dr_checkpolyagainstpoly(GEOM * geom,POLYGON * poly,GEOM * ogeom,POLYGON * opoly,BOOLEAN cancross)1576 BOOLEAN dr_checkpolyagainstpoly(GEOM *geom, POLYGON *poly, GEOM *ogeom, POLYGON *opoly, BOOLEAN cancross)
1577 {
1578 	REGISTER void *err;
1579 	REGISTER INTBIG i;
1580 
1581 	if (cancross)
1582 	{
1583 		for(i=0; i<poly->count; i++)
1584 		{
1585 			if (polydistance(opoly, poly->xv[i], poly->yv[i]) <= 0) break;
1586 		}
1587 		if (i >= poly->count)
1588 		{
1589 			/* none in "poly" touched one in "opoly", try other way */
1590 			for(i=0; i<opoly->count; i++)
1591 			{
1592 				if (polydistance(poly, opoly->xv[i], opoly->yv[i]) <= 0) break;
1593 			}
1594 			if (i >= opoly->count) return(FALSE);
1595 		}
1596 	} else
1597 	{
1598 		if (!polyintersect(poly, opoly)) return(FALSE);
1599 	}
1600 
1601 	/* report the error */
1602 	err = logerror(_("Objects touch"), geomparent(geom), 0);
1603 	addgeomtoerror(err, geom, TRUE, 0, 0);
1604 	addgeomtoerror(err, ogeom, TRUE, 0, 0);
1605 	return(TRUE);
1606 }
1607 
1608 /*
1609  * Routine to check whether arc "ai" is colinear with another.
1610  * Returns TRUE if an error was found.
1611  */
dr_schcheckcolinear(ARCINST * ai,ARCINST * oai)1612 BOOLEAN dr_schcheckcolinear(ARCINST *ai, ARCINST *oai)
1613 {
1614 	REGISTER INTBIG lowx, highx, lowy, highy, olow, ohigh, ang, oang, fx, fy, tx, ty,
1615 		ofx, ofy, otx, oty, dist, gdist, frx, fry, tox, toy, ca, sa;
1616 	REGISTER void *err;
1617 
1618 	/* get information about the other line */
1619 	fx = ai->end[0].xpos;   fy = ai->end[0].ypos;
1620 	tx = ai->end[1].xpos;   ty = ai->end[1].ypos;
1621 	ofx = oai->end[0].xpos;   ofy = oai->end[0].ypos;
1622 	otx = oai->end[1].xpos;   oty = oai->end[1].ypos;
1623 	if (ofx == otx && ofy == oty) return(FALSE);
1624 
1625 	/* see if they are colinear */
1626 	lowx = mini(fx, tx);
1627 	highx = maxi(fx, tx);
1628 	lowy = mini(fy, ty);
1629 	highy = maxi(fy, ty);
1630 	if (fx == tx)
1631 	{
1632 		/* vertical line */
1633 		olow = mini(ofy, oty);
1634 		ohigh = maxi(ofy, oty);
1635 		if (ofx != fx || otx != fx) return(FALSE);
1636 		if (lowy >= ohigh || highy <= olow) return(FALSE);
1637 		ang = 900;
1638 	} else if (fy == ty)
1639 	{
1640 		/* horizontal line */
1641 		olow = mini(ofx, otx);
1642 		ohigh = maxi(ofx, otx);
1643 		if (ofy != fy || oty != fy) return(FALSE);
1644 		if (lowx >= ohigh || highx <= olow) return(FALSE);
1645 		ang = 0;
1646 	} else
1647 	{
1648 		/* general case */
1649 		ang = figureangle(fx, fy, tx, ty);
1650 		oang = figureangle(ofx, ofy, otx, oty);
1651 		if (ang != oang && mini(ang, oang) + 1800 != maxi(ang, oang)) return(FALSE);
1652 		if (muldiv(ofx-fx, ty-fy, tx-fx) != ofy-fy) return(FALSE);
1653 		if (muldiv(otx-fx, ty-fy, tx-fx) != oty-fy) return(FALSE);
1654 		olow = mini(ofy, oty);
1655 		ohigh = maxi(ofy, oty);
1656 		if (lowy >= ohigh || highy <= olow) return(FALSE);
1657 		olow = mini(ofx, otx);
1658 		ohigh = maxi(ofx, otx);
1659 		if (lowx >= ohigh || highx <= olow) return(FALSE);
1660 	}
1661 	err = logerror(_("Arcs overlap"), ai->parent, 0);
1662 	addgeomtoerror(err, ai->geom, TRUE, 0, 0);
1663 	addgeomtoerror(err, oai->geom, TRUE, 0, 0);
1664 
1665 	/* add information that shows the arcs */
1666 	ang = (ang + 900) % 3600;
1667 	dist = ai->parent->lib->lambda[ai->parent->tech->techindex] * 2;
1668 	gdist = dist / 2;
1669 	ca = cosine(ang);   sa = sine(ang);
1670 	frx = fx + mult(dist, ca);
1671 	fry = fy + mult(dist, sa);
1672 	tox = tx + mult(dist, ca);
1673 	toy = ty + mult(dist, sa);
1674 	fx = fx + mult(gdist, ca);
1675 	fy = fy + mult(gdist, sa);
1676 	tx = tx + mult(gdist, ca);
1677 	ty = ty + mult(gdist, sa);
1678 	addlinetoerror(err, frx, fry, tox, toy);
1679 	addlinetoerror(err, frx, fry, fx, fy);
1680 	addlinetoerror(err, tx, ty, tox, toy);
1681 
1682 	frx = ofx - mult(dist, ca);
1683 	fry = ofy - mult(dist, sa);
1684 	tox = otx - mult(dist, ca);
1685 	toy = oty - mult(dist, sa);
1686 	ofx = ofx - mult(gdist, ca);
1687 	ofy = ofy - mult(gdist, sa);
1688 	otx = otx - mult(gdist, ca);
1689 	oty = oty - mult(gdist, sa);
1690 	addlinetoerror(err, frx, fry, tox, toy);
1691 	addlinetoerror(err, frx, fry, ofx, ofy);
1692 	addlinetoerror(err, otx, oty, tox, toy);
1693 	return(TRUE);
1694 }
1695 
1696 /****************************** DIALOGS ******************************/
1697 
1698 /* DRC: Options */
1699 static DIALOGITEM dr_optionsdialogitems[] =
1700 {
1701  /*  1 */ {0, {304,184,328,248}, BUTTON, N_("OK")},
1702  /*  2 */ {0, {304,44,328,108}, BUTTON, N_("Cancel")},
1703  /*  3 */ {0, {144,8,160,224}, MESSAGE, N_("Incremental and hierarchical:")},
1704  /*  4 */ {0, {272,32,288,160}, BUTTON, N_("Edit Rules Deck")},
1705  /*  5 */ {0, {32,32,48,117}, CHECK, N_("On")},
1706  /*  6 */ {0, {192,216,208,272}, EDITTEXT, x_("")},
1707  /*  7 */ {0, {8,8,24,169}, MESSAGE, N_("Incremental DRC:")},
1708  /*  8 */ {0, {64,8,80,169}, MESSAGE, N_("Hierarchical DRC:")},
1709  /*  9 */ {0, {248,8,264,169}, MESSAGE, N_("Dracula DRC Interface:")},
1710  /* 10 */ {0, {112,32,128,192}, BUTTON, N_("Clear valid DRC dates")},
1711  /* 11 */ {0, {88,32,104,228}, CHECK, N_("Just 1 error per cell")},
1712  /* 12 */ {0, {216,32,232,296}, CHECK, N_("Ignore center cuts in large contacts")},
1713  /* 13 */ {0, {192,48,208,212}, MESSAGE, N_("Number of processors:")},
1714  /* 14 */ {0, {168,32,184,217}, CHECK, N_("Use multiple processors")},
1715  /* 15 */ {0, {56,8,57,296}, DIVIDELINE, x_("")},
1716  /* 16 */ {0, {136,8,137,296}, DIVIDELINE, x_("")},
1717  /* 17 */ {0, {240,8,241,296}, DIVIDELINE, x_("")},
1718  /* 18 */ {0, {296,8,297,296}, DIVIDELINE, x_("")}
1719 };
1720 static DIALOG dr_optionsdialog = {{50,75,387,381}, N_("DRC Options"), 0, 18, dr_optionsdialogitems, 0, 0};
1721 
1722 /* special items for the "DRC Options" dialog: */
1723 #define DDRO_DRACULADECK   4		/* Edit dracula rules (button) */
1724 #define DDRO_DRCON         5		/* Incremental DRC is on (check) */
1725 #define DDRO_NUMPROC       6		/* Number of processors to use (edit text) */
1726 #define DDRO_CLEARDATES   10		/* Clear valid DRC dates (button) */
1727 #define DDRO_JUST1ERROR   11		/* Find 1 error per cell (check) */
1728 #define DDRO_FEWERCUTS    12		/* Ignore center cuts in large contacts (check) */
1729 #define DDRO_USEMULTIPROC 14		/* Use multiple processors (check) */
1730 
dr_optionsdlog(void)1731 void dr_optionsdlog(void)
1732 {
1733 	REGISTER INTBIG itemHit, options, oldoptions, i, l, numproc, orignumproc;
1734 	REGISTER CHAR *qual;
1735 	INTBIG dummy, clearvaliddrcdates;
1736 	CHAR header[200], *dummyfile[1];
1737 	REGISTER VARIABLE *var;
1738 	REGISTER WINDOWPART *w;
1739 	REGISTER EDITOR *ed;
1740 	REGISTER void *infstr, *dia;
1741 
1742 	dia = DiaInitDialog(&dr_optionsdialog);
1743 	if (dia == 0) return;
1744 	DiaUnDimItem(dia, DDRO_CLEARDATES);
1745 
1746 	oldoptions = dr_getoptionsvalue();
1747 	if ((oldoptions&DRCFIRSTERROR) != 0) DiaSetControl(dia, DDRO_JUST1ERROR, 1);
1748 	if ((oldoptions&DRCREASONABLE) != 0) DiaSetControl(dia, DDRO_FEWERCUTS, 1);
1749 	if ((dr_tool->toolstate & TOOLON) != 0) DiaSetControl(dia, DDRO_DRCON, 1);
1750 	if (graphicshas(CANDOTHREADS))
1751 	{
1752 		DiaUnDimItem(dia, DDRO_USEMULTIPROC);
1753 		orignumproc = numproc = (oldoptions&DRCNUMPROC) >> DRCNUMPROCSH;
1754 		if (numproc == 0) numproc = enumprocessors();
1755 		esnprintf(header, 200, x_("%ld"), numproc);
1756 		DiaSetText(dia, DDRO_NUMPROC, header);
1757 		if ((oldoptions&DRCMULTIPROC) != 0)
1758 		{
1759 			DiaSetControl(dia, DDRO_USEMULTIPROC, 1);
1760 			DiaUnDimItem(dia, DDRO_NUMPROC);
1761 		} else
1762 		{
1763 			DiaDimItem(dia, DDRO_NUMPROC);
1764 		}
1765 	} else
1766 	{
1767 		DiaDimItem(dia, DDRO_USEMULTIPROC);
1768 		DiaDimItem(dia, DDRO_NUMPROC);
1769 	}
1770 
1771 	/* loop until done */
1772 	for(;;)
1773 	{
1774 		itemHit = DiaNextHit(dia);
1775 		if (itemHit == OK || itemHit == CANCEL || itemHit == DDRO_DRACULADECK) break;
1776 		if (itemHit == DDRO_DRCON || itemHit == DDRO_JUST1ERROR ||
1777 			itemHit == DDRO_FEWERCUTS || itemHit == DDRO_USEMULTIPROC)
1778 		{
1779 			i = 1 - DiaGetControl(dia, itemHit);
1780 			DiaSetControl(dia, itemHit, i);
1781 			if (itemHit == DDRO_USEMULTIPROC)
1782 			{
1783 				if (i != 0) DiaUnDimItem(dia, DDRO_NUMPROC); else
1784 					DiaDimItem(dia, DDRO_NUMPROC);
1785 			}
1786 			continue;
1787 		}
1788 		if (itemHit == DDRO_CLEARDATES)
1789 		{
1790 			clearvaliddrcdates = 1;
1791 			DiaDimItem(dia, DDRO_CLEARDATES);
1792 			continue;
1793 		}
1794 	}
1795 
1796 	if (itemHit != CANCEL)
1797 	{
1798 		options = 0;
1799 		if (DiaGetControl(dia, DDRO_JUST1ERROR) != 0) options |= DRCFIRSTERROR;
1800 		if (DiaGetControl(dia, DDRO_FEWERCUTS) != 0) options |= DRCREASONABLE;
1801 		if (graphicshas(CANDOTHREADS))
1802 		{
1803 			if (DiaGetControl(dia, DDRO_USEMULTIPROC) != 0) options |= DRCMULTIPROC;
1804 			numproc = eatoi(DiaGetText(dia, DDRO_NUMPROC));
1805 			if (DiaGetControl(dia, DDRO_USEMULTIPROC) == 0)
1806 				numproc = orignumproc;
1807 			options = (options & ~DRCNUMPROC) | (numproc << DRCNUMPROCSH);
1808 		}
1809 		if (options != oldoptions)
1810 	 		(void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey, options, VINTEGER);
1811 
1812 		/* change state of DRC */
1813 		if (DiaGetControl(dia, DDRO_DRCON) != 0)
1814 		{
1815 			if ((dr_tool->toolstate & TOOLON) == 0)
1816 			{
1817 				toolturnon(dr_tool);
1818 				setvalkey((INTBIG)dr_tool, VTOOL, dr_incrementalonkey, 1, VINTEGER);
1819 			}
1820 		} else
1821 		{
1822 			if ((dr_tool->toolstate & TOOLON) != 0)
1823 			{
1824 				toolturnoff(dr_tool, FALSE);
1825 				setvalkey((INTBIG)dr_tool, VTOOL, dr_incrementalonkey, 0, VINTEGER);
1826 			}
1827 		}
1828 
1829 		/* clear valid DRC dates if requested */
1830 		if (clearvaliddrcdates != 0) dr_reset_dates();
1831 	}
1832 	DiaDoneDialog(dia);
1833 
1834 	if (itemHit == DDRO_DRACULADECK)
1835 	{
1836 		/* now edit the dracula */
1837 		qual = x_("DRC_ecad_deck");
1838 		esnprintf(header, 200, _("ECAD deck for technology %s"), el_curtech->techname);
1839 
1840 		var = getval((INTBIG)el_curtech, VTECHNOLOGY, -1, qual);
1841 		if (var == NOVARIABLE)
1842 		{
1843 			dummyfile[0] = x_("");
1844 			var = setval((INTBIG)el_curtech, VTECHNOLOGY, qual, (INTBIG)dummyfile,
1845 				VSTRING|VISARRAY|(1<<VLENGTHSH));
1846 			if (var == NOVARIABLE)
1847 			{
1848 				ttyputerr(_("Cannot create DRC_ecad_deck on the technology"));
1849 				return;
1850 			}
1851 		} else
1852 			var->type &= ~VDONTSAVE;
1853 
1854 		/* get a new window, put an editor in it */
1855 		w = us_wantnewwindow(0);
1856 		if (w == NOWINDOWPART) return;
1857 		if (us_makeeditor(w, header, &dummy, &dummy) == NOWINDOWPART) return;
1858 		ed = w->editor;
1859 		ed->editobjqual = qual;
1860 		ed->editobjaddr = (CHAR *)el_curtech;
1861 		ed->editobjtype = VTECHNOLOGY;
1862 		ed->editobjvar = var;
1863 		us_suspendgraphics(w);
1864 
1865 		l = getlength(var);
1866 		for(i=0; i<l; i++)
1867 		{
1868 			infstr = initinfstr();
1869 			addstringtoinfstr(infstr, describevariable(var, i, -1));
1870 			us_addline(w, i, returninfstr(infstr));
1871 		}
1872 		us_resumegraphics(w);
1873 		w->changehandler = us_varchanges;
1874 	}
1875 }
1876 
1877 /*
1878  * Routine to invoke the Design Rule Editing dialog on the current technology.
1879  */
dr_rulesdloghook(void)1880 void dr_rulesdloghook(void)
1881 {
1882 	REGISTER INTBIG i, changed, truelen, truelenR, truelencon, truelenuncon, truelenconW, truelenunconW,
1883 		truelenconM, truelenunconM, truelenedge, truelenconR, truelenunconR, truelenconWR, truelenunconWR,
1884 		truelenconMR, truelenunconMR, truelenedgeR;
1885 	REGISTER VARIABLE *varcon, *varuncon, *varconW, *varunconW, *varconM, *varunconM,
1886 		*varedge, *varconR, *varunconR, *varconWR, *varunconWR, *varconMR, *varunconMR,
1887 		*varedgeR, *varmindist, *varmindistR, *var, *varminsize, *varminsizeR;
1888 	REGISTER DRCRULES *rules;
1889 
1890 	/* create a RULES structure */
1891 	rules = dr_allocaterules(el_curtech->layercount, el_curtech->nodeprotocount, el_curtech->techname);
1892 	if (rules == NODRCRULES) return;
1893 
1894 	/* fill in the technology name and layer names */
1895 	for(i=0; i<rules->numlayers; i++)
1896 		(void)allocstring(&rules->layernames[i], layername(el_curtech, i), el_tempcluster);
1897 
1898 	/* get the distances */
1899 	varmindist = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1900 		dr_min_widthkey);
1901 	varmindistR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1902 		dr_min_width_rulekey);
1903 	varcon = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1904 		dr_connected_distanceskey);
1905 	varuncon = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1906 		dr_unconnected_distanceskey);
1907 	varconW = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1908 		dr_connected_distancesWkey);
1909 	varunconW = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1910 		dr_unconnected_distancesWkey);
1911 	varconM = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1912 		dr_connected_distancesMkey);
1913 	varunconM = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1914 		dr_unconnected_distancesMkey);
1915 	varedge = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1916 		dr_edge_distanceskey);
1917 	varminsize = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1918 		dr_min_node_sizekey);
1919 	varconR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1920 		dr_connected_distances_rulekey);
1921 	varunconR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1922 		dr_unconnected_distances_rulekey);
1923 	varconWR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1924 		dr_connected_distancesW_rulekey);
1925 	varunconWR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1926 		dr_unconnected_distancesW_rulekey);
1927 	varconMR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1928 		dr_connected_distancesM_rulekey);
1929 	varunconMR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1930 		dr_unconnected_distancesM_rulekey);
1931 	varedgeR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1932 		dr_edge_distances_rulekey);
1933 	varminsizeR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1934 		dr_min_node_size_rulekey);
1935 
1936 	/* put the distances into the rules structure */
1937 	if (varmindist == NOVARIABLE) truelen = 0; else
1938 		truelen = getlength(varmindist);
1939 	if (varmindistR == NOVARIABLE) truelenR = 0; else
1940 		truelenR = getlength(varmindistR);
1941 	for(i=0; i<rules->numlayers; i++)
1942 	{
1943 		if (i < truelen)
1944 			rules->minwidth[i] = ((INTBIG *)varmindist->addr)[i];
1945 		if (i < truelenR && ((CHAR **)varmindistR->addr)[i][0] != 0)
1946 			(void)reallocstring(&rules->minwidthR[i], ((CHAR **)varmindistR->addr)[i], el_tempcluster);
1947 	}
1948 	if (varcon == NOVARIABLE) truelencon = 0; else
1949 		truelencon = getlength(varcon);
1950 	if (varuncon == NOVARIABLE) truelenuncon = 0; else
1951 		truelenuncon = getlength(varuncon);
1952 	if (varconW == NOVARIABLE) truelenconW = 0; else
1953 		truelenconW = getlength(varconW);
1954 	if (varunconW == NOVARIABLE) truelenunconW = 0; else
1955 		truelenunconW = getlength(varunconW);
1956 	if (varconM == NOVARIABLE) truelenconM = 0; else
1957 		truelenconM = getlength(varconM);
1958 	if (varunconM == NOVARIABLE) truelenunconM = 0; else
1959 		truelenunconM = getlength(varunconM);
1960 	if (varedge == NOVARIABLE) truelenedge = 0; else
1961 		truelenedge = getlength(varedge);
1962 
1963 	if (varconR == NOVARIABLE) truelenconR = 0; else
1964 		truelenconR = getlength(varconR);
1965 	if (varunconR == NOVARIABLE) truelenunconR = 0; else
1966 		truelenunconR = getlength(varunconR);
1967 	if (varconWR == NOVARIABLE) truelenconWR = 0; else
1968 		truelenconWR = getlength(varconWR);
1969 	if (varunconWR == NOVARIABLE) truelenunconWR = 0; else
1970 		truelenunconWR = getlength(varunconWR);
1971 	if (varconMR == NOVARIABLE) truelenconMR = 0; else
1972 		truelenconMR = getlength(varconMR);
1973 	if (varunconMR == NOVARIABLE) truelenunconMR = 0; else
1974 		truelenunconMR = getlength(varunconMR);
1975 	if (varedgeR == NOVARIABLE) truelenedgeR = 0; else
1976 		truelenedgeR = getlength(varedgeR);
1977 
1978 	for(i=0; i<rules->utsize; i++)
1979 	{
1980 		if (i < truelencon)
1981 			rules->conlist[i] = ((INTBIG *)varcon->addr)[i];
1982 		if (i < truelenuncon)
1983 			rules->unconlist[i] = ((INTBIG *)varuncon->addr)[i];
1984 		if (i < truelenconW)
1985 			rules->conlistW[i] = ((INTBIG *)varconW->addr)[i];
1986 		if (i < truelenunconW)
1987 			rules->unconlistW[i] = ((INTBIG *)varunconW->addr)[i];
1988 		if (i < truelenconM)
1989 			rules->conlistM[i] = ((INTBIG *)varconM->addr)[i];
1990 		if (i < truelenunconM)
1991 			rules->unconlistM[i] = ((INTBIG *)varunconM->addr)[i];
1992 		if (i < truelenedge)
1993 			rules->edgelist[i] = ((INTBIG *)varedge->addr)[i];
1994 
1995 		if (i < truelenconR && ((CHAR **)varconR->addr)[i][0] != 0)
1996 			(void)reallocstring(&rules->conlistR[i], ((CHAR **)varconR->addr)[i], el_tempcluster);
1997 		if (i < truelenunconR && ((CHAR **)varunconR->addr)[i][0] != 0)
1998 			(void)reallocstring(&rules->unconlistR[i], ((CHAR **)varunconR->addr)[i], el_tempcluster);
1999 		if (i < truelenconWR && ((CHAR **)varconWR->addr)[i][0] != 0)
2000 			(void)reallocstring(&rules->conlistWR[i], ((CHAR **)varconWR->addr)[i], el_tempcluster);
2001 		if (i < truelenunconWR && ((CHAR **)varunconWR->addr)[i][0] != 0)
2002 			(void)reallocstring(&rules->unconlistWR[i], ((CHAR **)varunconWR->addr)[i], el_tempcluster);
2003 		if (i < truelenconMR && ((CHAR **)varconMR->addr)[i][0] != 0)
2004 			(void)reallocstring(&rules->conlistMR[i], ((CHAR **)varconMR->addr)[i], el_tempcluster);
2005 		if (i < truelenunconMR && ((CHAR **)varunconMR->addr)[i][0] != 0)
2006 			(void)reallocstring(&rules->unconlistMR[i], ((CHAR **)varunconMR->addr)[i], el_tempcluster);
2007 		if (i < truelenedgeR && ((CHAR **)varedgeR->addr)[i][0] != 0)
2008 			(void)reallocstring(&rules->edgelistR[i], ((CHAR **)varedgeR->addr)[i], el_tempcluster);
2009 	}
2010 	var = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT, dr_wide_limitkey);
2011 	if (var != NOVARIABLE) rules->widelimit = var->addr;
2012 
2013 	/* get the node minimum size information */
2014 	if (varminsize == NOVARIABLE) truelen = 0; else
2015 		truelen = getlength(varminsize);
2016 	if (varminsizeR == NOVARIABLE) truelenR = 0; else
2017 		truelenR = getlength(varminsizeR);
2018 	for(i=0; i<rules->numnodes; i++)
2019 	{
2020 		rules->nodenames[i] = el_curtech->nodeprotos[i]->nodename;
2021 		if (i < truelen)
2022 		{
2023 			rules->minnodesize[i*2] = ((INTBIG *)varminsize->addr)[i*2];
2024 			rules->minnodesize[i*2+1] = ((INTBIG *)varminsize->addr)[i*2+1];
2025 		}
2026 		if (i < truelenR && ((CHAR **)varminsizeR->addr)[i][0] != 0)
2027 			(void)reallocstring(&rules->minnodesizeR[i], ((CHAR **)varminsizeR->addr)[i], el_tempcluster);
2028 	}
2029 
2030 	/* run the DRC editing dialog */
2031 	changed = dr_rulesdlog(el_curtech, rules);
2032 
2033 	/* if values changed, update variables */
2034 	if (changed != 0)
2035 	{
2036 		if ((changed&RULECHANGEMINWID) != 0)
2037 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_widthkey,
2038 				(INTBIG)rules->minwidth, VFRACT|VISARRAY|(rules->numlayers<<VLENGTHSH));
2039 		if ((changed&RULECHANGEMINWIDR) != 0)
2040 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_width_rulekey,
2041 				(INTBIG)rules->minwidthR, VSTRING|VISARRAY|(rules->numlayers<<VLENGTHSH));
2042 		if ((changed&RULECHANGECONSPA) != 0)
2043 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distanceskey,
2044 				(INTBIG)rules->conlist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2045 		if ((changed&RULECHANGEUCONSPA) != 0)
2046 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distanceskey,
2047 				(INTBIG)rules->unconlist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2048 		if ((changed&RULECHANGECONSPAW) != 0)
2049 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesWkey,
2050 				(INTBIG)rules->conlistW, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2051 		if ((changed&RULECHANGEUCONSPAW) != 0)
2052 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesWkey,
2053 				(INTBIG)rules->unconlistW, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2054 		if ((changed&RULECHANGECONSPAM) != 0)
2055 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesMkey,
2056 				(INTBIG)rules->conlistM, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2057 		if ((changed&RULECHANGEUCONSPAM) != 0)
2058 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesMkey,
2059 				(INTBIG)rules->unconlistM, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2060 		if ((changed&RULECHANGEEDGESPA) != 0)
2061 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_edge_distanceskey,
2062 				(INTBIG)rules->edgelist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2063 		if ((changed&RULECHANGECONSPAR) != 0)
2064 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distances_rulekey,
2065 				(INTBIG)rules->conlistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2066 		if ((changed&RULECHANGEUCONSPAR) != 0)
2067 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distances_rulekey,
2068 				(INTBIG)rules->unconlistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2069 		if ((changed&RULECHANGECONSPAWR) != 0)
2070 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesW_rulekey,
2071 				(INTBIG)rules->conlistWR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2072 		if ((changed&RULECHANGEUCONSPAWR) != 0)
2073 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesW_rulekey,
2074 				(INTBIG)rules->unconlistWR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2075 		if ((changed&RULECHANGECONSPAMR) != 0)
2076 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesM_rulekey,
2077 				(INTBIG)rules->conlistMR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2078 		if ((changed&RULECHANGEUCONSPAMR) != 0)
2079 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesM_rulekey,
2080 				(INTBIG)rules->unconlistMR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2081 		if ((changed&RULECHANGEEDGESPAR) != 0)
2082 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_edge_distances_rulekey,
2083 				(INTBIG)rules->edgelistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2084 		if ((changed&RULECHANGEWIDLIMIT) != 0)
2085 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_wide_limitkey,
2086 				rules->widelimit, VFRACT);
2087 
2088 		if ((changed&RULECHANGEMINSIZE) != 0)
2089 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_node_sizekey,
2090 				(INTBIG)rules->minnodesize, VFRACT|VISARRAY|((rules->numnodes*2)<<VLENGTHSH));
2091 		if ((changed&RULECHANGEMINSIZER) != 0)
2092 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_node_size_rulekey,
2093 				(INTBIG)rules->minnodesizeR, VSTRING|VISARRAY|(rules->numnodes<<VLENGTHSH));
2094 
2095 		/* reset valid DRC dates */
2096 		dr_reset_dates();
2097 	}
2098 
2099 	/* free the rules structure */
2100 	dr_freerules(rules);
2101 }
2102 
2103 /*
2104  * Routine to allocate the space for a DRC rules object that describes "layercount" layers.
2105  * Returns NODRCRULES on error.
2106  */
dr_allocaterules(INTBIG layercount,INTBIG nodecount,CHAR * techname)2107 DRCRULES *dr_allocaterules(INTBIG layercount, INTBIG nodecount, CHAR *techname)
2108 {
2109 	DRCRULES *rules;
2110 	REGISTER INTBIG i;
2111 
2112 	rules = (DRCRULES *)emalloc(sizeof (DRCRULES), el_tempcluster);
2113 	if (rules == 0) return(NODRCRULES);
2114 
2115 	(void)allocstring(&rules->techname, techname, el_tempcluster);
2116 
2117 	/* cache the spacing rules for this technology */
2118 	rules->numlayers = layercount;
2119 	rules->utsize = (layercount * layercount - layercount) / 2 + layercount;
2120 	rules->layernames = (CHAR **)emalloc(rules->numlayers * (sizeof (CHAR *)), el_tempcluster);
2121 	if (rules->layernames == 0) return(NODRCRULES);
2122 	rules->minwidth = (INTBIG *)emalloc(rules->numlayers * SIZEOFINTBIG, el_tempcluster);
2123 	if (rules->minwidth == 0) return(NODRCRULES);
2124 	rules->minwidthR = (CHAR **)emalloc(rules->numlayers * (sizeof (CHAR *)), el_tempcluster);
2125 	if (rules->minwidthR == 0) return(NODRCRULES);
2126 	rules->conlist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2127 	if (rules->conlist == 0) return(NODRCRULES);
2128 	rules->unconlist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2129 	if (rules->unconlist == 0) return(NODRCRULES);
2130 	rules->conlistW = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2131 	if (rules->conlistW == 0) return(NODRCRULES);
2132 	rules->unconlistW = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2133 	if (rules->unconlistW == 0) return(NODRCRULES);
2134 	rules->conlistM = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2135 	if (rules->conlistM == 0) return(NODRCRULES);
2136 	rules->unconlistM = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2137 	if (rules->unconlistM == 0) return(NODRCRULES);
2138 	rules->edgelist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2139 	if (rules->edgelist == 0) return(NODRCRULES);
2140 
2141 	rules->conlistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2142 	if (rules->conlistR == 0) return(NODRCRULES);
2143 	rules->unconlistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2144 	if (rules->unconlistR == 0) return(NODRCRULES);
2145 	rules->conlistWR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2146 	if (rules->conlistWR == 0) return(NODRCRULES);
2147 	rules->unconlistWR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2148 	if (rules->unconlistWR == 0) return(NODRCRULES);
2149 	rules->conlistMR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2150 	if (rules->conlistMR == 0) return(NODRCRULES);
2151 	rules->unconlistMR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2152 	if (rules->unconlistMR == 0) return(NODRCRULES);
2153 	rules->edgelistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2154 	if (rules->edgelistR == 0) return(NODRCRULES);
2155 
2156 	for(i=0; i<rules->numlayers; i++)
2157 	{
2158 		rules->minwidth[i] = XX;
2159 		(void)allocstring(&rules->minwidthR[i], x_(""), el_tempcluster);
2160 		rules->layernames[i] = 0;
2161 	}
2162 	for(i=0; i<rules->utsize; i++)
2163 	{
2164 		rules->conlist[i] = XX;
2165 		rules->unconlist[i] = XX;
2166 		rules->conlistW[i] = XX;
2167 		rules->unconlistW[i] = XX;
2168 		rules->conlistM[i] = XX;
2169 		rules->unconlistM[i] = XX;
2170 		rules->edgelist[i] = XX;
2171 		(void)allocstring(&rules->conlistR[i], x_(""), el_tempcluster);
2172 		(void)allocstring(&rules->unconlistR[i], x_(""), el_tempcluster);
2173 		(void)allocstring(&rules->conlistWR[i], x_(""), el_tempcluster);
2174 		(void)allocstring(&rules->unconlistWR[i], x_(""), el_tempcluster);
2175 		(void)allocstring(&rules->conlistMR[i], x_(""), el_tempcluster);
2176 		(void)allocstring(&rules->unconlistMR[i], x_(""), el_tempcluster);
2177 		(void)allocstring(&rules->edgelistR[i], x_(""), el_tempcluster);
2178 	}
2179 	rules->widelimit = K10;
2180 
2181 	/* allocate space for node rules */
2182 	rules->numnodes = nodecount;
2183 	if (nodecount > 0)
2184 	{
2185 		rules->nodenames = (CHAR **)emalloc(nodecount * (sizeof (CHAR *)), el_tempcluster);
2186 		if (rules->nodenames == 0) return(NODRCRULES);
2187 		rules->minnodesize = (INTBIG *)emalloc(nodecount * 2 * SIZEOFINTBIG, el_tempcluster);
2188 		if (rules->minnodesize == 0) return(NODRCRULES);
2189 		rules->minnodesizeR = (CHAR **)emalloc(nodecount * (sizeof (CHAR *)), el_tempcluster);
2190 		if (rules->minnodesizeR == 0) return(NODRCRULES);
2191 		for(i=0; i<nodecount; i++)
2192 		{
2193 			rules->minnodesize[i*2] = XX;
2194 			rules->minnodesize[i*2+1] = XX;
2195 			(void)allocstring(&rules->minnodesizeR[i], x_(""), el_tempcluster);
2196 		}
2197 	}
2198 	return(rules);
2199 }
2200 
2201 /*
2202  * Routine to free the DRCRULES structure in "rules".
2203  */
dr_freerules(DRCRULES * rules)2204 void dr_freerules(DRCRULES *rules)
2205 {
2206 	REGISTER INTBIG i;
2207 
2208 	efree((CHAR *)rules->techname);
2209 	efree((CHAR *)rules->conlist);
2210 	efree((CHAR *)rules->unconlist);
2211 	efree((CHAR *)rules->conlistW);
2212 	efree((CHAR *)rules->unconlistW);
2213 	efree((CHAR *)rules->conlistM);
2214 	efree((CHAR *)rules->unconlistM);
2215 	efree((CHAR *)rules->edgelist);
2216 	efree((CHAR *)rules->minwidth);
2217 	for(i=0; i<rules->utsize; i++)
2218 	{
2219 		efree((CHAR *)rules->conlistR[i]);
2220 		efree((CHAR *)rules->unconlistR[i]);
2221 		efree((CHAR *)rules->conlistWR[i]);
2222 		efree((CHAR *)rules->unconlistWR[i]);
2223 		efree((CHAR *)rules->conlistMR[i]);
2224 		efree((CHAR *)rules->unconlistMR[i]);
2225 		efree((CHAR *)rules->edgelistR[i]);
2226 	}
2227 	for(i=0; i<rules->numlayers; i++)
2228 	{
2229 		efree((CHAR *)rules->minwidthR[i]);
2230 		if (rules->layernames[i] != 0)
2231 			efree((CHAR *)rules->layernames[i]);
2232 	}
2233 	for(i=0; i<rules->numnodes; i++)
2234 		efree((CHAR *)rules->minnodesizeR[i]);
2235 	if (rules->numnodes > 0)
2236 	{
2237 		efree((CHAR *)rules->nodenames);
2238 		efree((CHAR *)rules->minnodesize);
2239 		efree((CHAR *)rules->minnodesizeR);
2240 	}
2241 	efree((CHAR *)rules->conlistR);
2242 	efree((CHAR *)rules->unconlistR);
2243 	efree((CHAR *)rules->conlistWR);
2244 	efree((CHAR *)rules->unconlistWR);
2245 	efree((CHAR *)rules->conlistMR);
2246 	efree((CHAR *)rules->unconlistMR);
2247 	efree((CHAR *)rules->edgelistR);
2248 	efree((CHAR *)rules->minwidthR);
2249 	efree((CHAR *)rules->layernames);
2250 }
2251 
2252 /****************************** DESIGN-RULE EDITING DIALOG ******************************/
2253 
2254 /* DRC: Rules */
2255 static DIALOGITEM dr_rulesdialogitems[] =
2256 {
2257  /*  1 */ {0, {8,516,32,580}, BUTTON, N_("OK")},
2258  /*  2 */ {0, {40,516,64,580}, BUTTON, N_("Cancel")},
2259  /*  3 */ {0, {32,100,188,278}, SCROLL, x_("")},
2260  /*  4 */ {0, {32,8,48,95}, RADIO, N_("Layers:")},
2261  /*  5 */ {0, {212,8,435,300}, SCROLL, x_("")},
2262  /*  6 */ {0, {8,100,24,294}, MESSAGE|INACTIVE, x_("")},
2263  /*  7 */ {0, {8,8,24,95}, MESSAGE, N_("Technology:")},
2264  /*  8 */ {0, {192,8,208,88}, MESSAGE, N_("To Layer:")},
2265  /*  9 */ {0, {88,452,104,523}, MESSAGE, N_("Size")},
2266  /* 10 */ {0, {88,528,104,583}, MESSAGE, N_("Rule")},
2267  /* 11 */ {0, {112,308,128,424}, MESSAGE, N_("Minimum Width:")},
2268  /* 12 */ {0, {112,454,128,502}, EDITTEXT, x_("")},
2269  /* 13 */ {0, {112,514,128,596}, EDITTEXT, x_("")},
2270  /* 14 */ {0, {180,308,196,387}, MESSAGE, N_("Normal:")},
2271  /* 15 */ {0, {204,324,220,450}, MESSAGE, N_("When connected:")},
2272  /* 16 */ {0, {204,454,220,502}, EDITTEXT, x_("")},
2273  /* 17 */ {0, {204,514,220,595}, EDITTEXT, x_("")},
2274  /* 18 */ {0, {232,324,248,450}, MESSAGE, N_("Not connected:")},
2275  /* 19 */ {0, {232,454,248,502}, EDITTEXT, x_("")},
2276  /* 20 */ {0, {232,514,248,595}, EDITTEXT, x_("")},
2277  /* 21 */ {0, {288,308,304,520}, MESSAGE, N_("Wide (when bigger than this):")},
2278  /* 22 */ {0, {312,324,328,450}, MESSAGE, N_("When connected:")},
2279  /* 23 */ {0, {312,454,328,502}, EDITTEXT, x_("")},
2280  /* 24 */ {0, {312,514,328,595}, EDITTEXT, x_("")},
2281  /* 25 */ {0, {340,324,356,450}, MESSAGE, N_("Not connected:")},
2282  /* 26 */ {0, {340,454,356,502}, EDITTEXT, x_("")},
2283  /* 27 */ {0, {340,514,356,595}, EDITTEXT, x_("")},
2284  /* 28 */ {0, {368,308,384,448}, MESSAGE, N_("Multiple cuts:")},
2285  /* 29 */ {0, {392,324,408,450}, MESSAGE, N_("When connected:")},
2286  /* 30 */ {0, {392,454,408,502}, EDITTEXT, x_("")},
2287  /* 31 */ {0, {392,514,408,595}, EDITTEXT, x_("")},
2288  /* 32 */ {0, {420,324,436,450}, MESSAGE, N_("Not connected:")},
2289  /* 33 */ {0, {420,454,436,502}, EDITTEXT, x_("")},
2290  /* 34 */ {0, {420,514,436,595}, EDITTEXT, x_("")},
2291  /* 35 */ {0, {180,452,196,523}, MESSAGE, N_("Distance")},
2292  /* 36 */ {0, {180,528,196,583}, MESSAGE, N_("Rule")},
2293  /* 37 */ {0, {24,328,48,488}, BUTTON, N_("Factory Reset of Rules")},
2294  /* 38 */ {0, {288,526,304,574}, EDITTEXT, x_("")},
2295  /* 39 */ {0, {260,324,276,450}, MESSAGE, N_("Edge:")},
2296  /* 40 */ {0, {260,454,276,502}, EDITTEXT, x_("")},
2297  /* 41 */ {0, {260,514,276,595}, EDITTEXT, x_("")},
2298  /* 42 */ {0, {192,104,208,300}, CHECK, N_("Show only lines with rules")},
2299  /* 43 */ {0, {56,8,72,95}, RADIO, N_("Nodes:")},
2300  /* 44 */ {0, {136,308,152,424}, MESSAGE, N_("Minimum Height:")},
2301  /* 45 */ {0, {136,454,152,502}, EDITTEXT, x_("")}
2302 };
2303 static DIALOG dr_rulesdialog = {{50,75,495,681}, N_("Design Rules"), 0, 45, dr_rulesdialogitems, 0, 0};
2304 
2305 static void       dr_loaddrcdialog(DRCRULES *rules, INTBIG *validlayers, void *dia);
2306 static void       dr_loaddrcruleobjects(DRCRULES *rules, INTBIG *validlayers, void *dia);
2307 static void       dr_loaddrcdistance(DRCRULES *rules, void *dia);
2308 static CHAR      *dr_loadoptlistline(DRCRULES *rules, INTBIG dindex, INTBIG lindex, INTBIG onlyvalid);
2309 static INTBIG     dr_rulesdialoggetlayer(DRCRULES *rules, INTBIG item, void *dia);
2310 
2311 /* special items for the "DRC Rules" dialog: */
2312 #define DDRR_FROMLAYER     3		/* From layer (scroll) */
2313 #define DDRR_SHOWLAYERS    4		/* Show layers in upper list (check) */
2314 #define DDRR_TOLAYER       5		/* To layer (scroll) */
2315 #define DDRR_TECHNAME      6		/* Technology name (stat text) */
2316 #define DDRR_TOLAYER_L     8		/* To layer label (message) */
2317 #define DDRR_MINWIDTH     12		/* Minimum width (edit text) */
2318 #define DDRR_MINWIDTHR    13		/* Minimum width rule (edit text) */
2319 #define DDRR_NORMDIST_L   14		/* Normal distance label (message) */
2320 #define DDRR_CONDIST_L    15		/* Connected distance label (message) */
2321 #define DDRR_CONDIST      16		/* Connected distance (edit text) */
2322 #define DDRR_CONDISTR     17		/* Connected distance rule (edit text) */
2323 #define DDRR_UCONDIST_L   18		/* Unconnected distance label (message) */
2324 #define DDRR_UCONDIST     19		/* Unconnected distance (edit text) */
2325 #define DDRR_UCONDISTR    20		/* Unconnected distance rule (edit text) */
2326 #define DDRR_WIDEDIST_L   21		/* Wide distance label (message) */
2327 #define DDRR_CONDISTW_L   22		/* Connected wide distance label (message) */
2328 #define DDRR_CONDISTW     23		/* Connected wide distance (edit text) */
2329 #define DDRR_CONDISTWR    24		/* Connected wide distance rule (edit text) */
2330 #define DDRR_UCONDISTW_L  25		/* Unconnected wide distance label (message) */
2331 #define DDRR_UCONDISTW    26		/* Unconnected wide distance (edit text) */
2332 #define DDRR_UCONDISTWR   27		/* Unconnected wide distance rule (edit text) */
2333 #define DDRR_MULTIDIST_L  28		/* Multicut distance label (message) */
2334 #define DDRR_CONDISTM_L   29		/* Connected multi distance label (message) */
2335 #define DDRR_CONDISTM     30		/* Connected multi distance (edit text) */
2336 #define DDRR_CONDISTMR    31		/* Connected multi distance rule (edit text) */
2337 #define DDRR_UCONDISTM_L  32		/* Unconnected multi distance label (message) */
2338 #define DDRR_UCONDISTM    33		/* Unconnected multi distance (edit text) */
2339 #define DDRR_UCONDISTMR   34		/* Unconnected multi distance rule (edit text) */
2340 #define DDRR_DIST_L       35		/* Spacing distance label (message) */
2341 #define DDRR_DISTR_L      36		/* Spacing rule label (message) */
2342 #define DDRR_FACTORYRST   37		/* Factor Reset (button) */
2343 #define DDRR_WIDELIMIT    38		/* Wide limit (edit text) */
2344 #define DDRR_EDGEDIST_L   39		/* Edge distance label (message) */
2345 #define DDRR_EDGEDIST     40		/* Edge distance (edit text) */
2346 #define DDRR_EDGEDISTR    41		/* Edge distance rule (edit text) */
2347 #define DDRR_VALIDRULES   42		/* Only show lines with rules (check) */
2348 #define DDRR_SHOWNODES    43		/* Show nodes in upper list (check) */
2349 #define DDRR_MINHEIGHT_L  44		/* Minimum height label (message) */
2350 #define DDRR_MINHEIGHT    45		/* Minimum height (edit text) */
2351 
2352 /*
2353  * Routine to implement a dialog for design rule editing.  This is called from the design-rule checker
2354  * to edit current rules, and it is called by the technology editor to edit rules from technologies
2355  * under construction.  Takes a technology name ("techname"), number of layers ("numlayers"), and
2356  * the layer names ("layernames").  Takes all of the design-rule tables:
2357  *   "minwidth" and "minwidthR", the minimum width and rule for each layer
2358  *   "conlist" and "conlistR", the distances and rules between connected layers
2359  *   "unconlist" and "unconlistR", the distances and rules between unconnected layers
2360  *   "conlistW" and "conlistWR", the distances and rules between connected layers that are wide
2361  *   "unconlistW" and "unconlistWR", the distances and rules between unconnected layers that are wide
2362  *   "conlistM" and "conlistMR", the distances and rules between connected layers on multi-cut contacts
2363  *   "unconlistM" and "unconlistMR", the distances and rules between unconnected layers on multi-cut contacts
2364  * Returns bits that indicate which values changed.
2365  */
dr_rulesdlog(TECHNOLOGY * tech,DRCRULES * rules)2366 INTBIG dr_rulesdlog(TECHNOLOGY *tech, DRCRULES *rules)
2367 {
2368 	REGISTER INTBIG itemHit, i, j, dist, layer1, layer2, temp, dindex, *validlayers, changed;
2369 	REGISTER NODEINST *ni;
2370 	REGISTER ARCINST *ai;
2371 	REGISTER NODEPROTO *np;
2372 	NODEINST node;
2373 	ARCINST arc;
2374 	REGISTER ARCPROTO *ap;
2375 	REGISTER CHAR *pt, *varname;
2376 	REGISTER POLYGON *poly;
2377 	REGISTER void *dia;
2378 
2379 	/* determine which layers are valid */
2380 	validlayers = (INTBIG *)emalloc(rules->numlayers * SIZEOFINTBIG, dr_tool->cluster);
2381 	if (validlayers == 0) return(0);
2382 	if (tech == NOTECHNOLOGY)
2383 	{
2384 		/* designing rules in technology edit: all layers are valid */
2385 		for(i=0; i<rules->numlayers; i++) validlayers[i] = 1;
2386 	} else
2387 	{
2388 		/* editing rules for technology: find used layers only */
2389 		poly = allocpolygon(4, dr_tool->cluster);
2390 		for(i=0; i<rules->numlayers; i++) validlayers[i] = 0;
2391 		for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2392 		{
2393 			if ((np->userbits&NNOTUSED) != 0) continue;
2394 			ni = &node;   initdummynode(ni);
2395 			ni->proto = np;
2396 			ni->lowx = np->lowx;   ni->highx = np->highx;
2397 			ni->lowy = np->lowy;   ni->highy = np->highy;
2398 			j = nodepolys(ni, 0, NOWINDOWPART);
2399 			for(i=0; i<j; i++)
2400 			{
2401 				shapenodepoly(ni, i, poly);
2402 				if (poly->tech != tech) continue;
2403 				validlayers[poly->layer] = 1;
2404 			}
2405 		}
2406 		for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2407 		{
2408 			if ((ap->userbits&ANOTUSED) != 0) continue;
2409 			ai = &arc;   initdummyarc(ai);
2410 			ai->proto = ap;
2411 			ai->width = ap->nominalwidth;
2412 			j = arcpolys(ai, NOWINDOWPART);
2413 			for(i=0; i<j; i++)
2414 			{
2415 				shapearcpoly(ai, i, poly);
2416 				if (poly->tech != tech) continue;
2417 				validlayers[poly->layer] = 1;
2418 			}
2419 		}
2420 		freepolygon(poly);
2421 	}
2422 
2423 	dia = DiaInitDialog(&dr_rulesdialog);
2424 	if (dia == 0) return(0);
2425 	DiaInitTextDialog(dia, DDRR_FROMLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
2426 		SCSELMOUSE|SCREPORT);
2427 	DiaInitTextDialog(dia, DDRR_TOLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
2428 		SCSELMOUSE|SCREPORT);
2429 	if (tech == NOTECHNOLOGY) DiaDimItem(dia, DDRR_FACTORYRST); else
2430 		DiaUnDimItem(dia, DDRR_FACTORYRST);
2431 
2432 	/* make the layer list */
2433 	DiaSetControl(dia, DDRR_SHOWLAYERS, 1);
2434 	dr_loaddrcruleobjects(rules, validlayers, dia);
2435 
2436 	DiaSetText(dia, DDRR_TECHNAME, rules->techname);
2437 	DiaSetText(dia, DDRR_WIDELIMIT, frtoa(rules->widelimit));
2438 
2439 	dr_loaddrcdialog(rules, validlayers, dia);
2440 	dr_loaddrcdistance(rules, dia);
2441 	changed = 0;
2442 
2443 	/* loop until done */
2444 	for(;;)
2445 	{
2446 		itemHit = DiaNextHit(dia);
2447 		if (itemHit == OK || itemHit == CANCEL || itemHit == DDRR_FACTORYRST) break;
2448 		if (itemHit == DDRR_SHOWLAYERS || itemHit == DDRR_SHOWNODES)
2449 		{
2450 			DiaSetControl(dia, DDRR_SHOWLAYERS, 0);
2451 			DiaSetControl(dia, DDRR_SHOWNODES, 0);
2452 			DiaSetControl(dia, itemHit, 1);
2453 			dr_loaddrcruleobjects(rules, validlayers, dia);
2454 			dr_loaddrcdialog(rules, validlayers, dia);
2455 			continue;
2456 		}
2457 		if (itemHit == DDRR_CONDIST || itemHit == DDRR_UCONDIST ||
2458 			itemHit == DDRR_CONDISTW || itemHit == DDRR_UCONDISTW ||
2459 			itemHit == DDRR_CONDISTM || itemHit == DDRR_UCONDISTM ||
2460 			itemHit == DDRR_EDGEDIST)
2461 		{
2462 			/* typed into distance field */
2463 			i = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2464 			if (i < 0) continue;
2465 			pt = DiaGetText(dia, itemHit);
2466 			while (*pt == ' ' || *pt == '\t') pt++;
2467 			if (*pt == 0) dist = -WHOLE; else
2468 				dist = atofr(pt);
2469 			layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2470 			if (layer1 < 0) continue;
2471 			layer2 = i;
2472 			if (layer1 > layer2) { temp = layer1; layer1 = layer2;  layer2 = temp; }
2473 			dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2474 			dindex = layer2 + rules->numlayers * layer1 - dindex;
2475 			if (itemHit == DDRR_CONDIST)
2476 			{
2477 				if (rules->conlist[dindex] != dist) changed |= RULECHANGECONSPA;
2478 				rules->conlist[dindex] = dist;
2479 			} else if (itemHit == DDRR_UCONDIST)
2480 			{
2481 				if (rules->unconlist[dindex] != dist) changed |= RULECHANGEUCONSPA;
2482 				rules->unconlist[dindex] = dist;
2483 			} else if (itemHit == DDRR_CONDISTW)
2484 			{
2485 				if (rules->conlistW[dindex] != dist) changed |= RULECHANGECONSPAW;
2486 				rules->conlistW[dindex] = dist;
2487 			} else if (itemHit == DDRR_UCONDISTW)
2488 			{
2489 				if (rules->unconlistW[dindex] != dist) changed |= RULECHANGEUCONSPAW;
2490 				rules->unconlistW[dindex] = dist;
2491 			} else if (itemHit == DDRR_CONDISTM)
2492 			{
2493 				if (rules->conlistM[dindex] != dist) changed |= RULECHANGECONSPAM;
2494 				rules->conlistM[dindex] = dist;
2495 			} else if (itemHit == DDRR_UCONDISTM)
2496 			{
2497 				if (rules->unconlistM[dindex] != dist) changed |= RULECHANGEUCONSPAM;
2498 				rules->unconlistM[dindex] = dist;
2499 			} else if (itemHit == DDRR_EDGEDIST)
2500 			{
2501 				if (rules->edgelist[dindex] != dist) changed |= RULECHANGEEDGESPA;
2502 				rules->edgelist[dindex] = dist;
2503 			}
2504 
2505 			pt = dr_loadoptlistline(rules, dindex, i, 0);
2506 			DiaSetScrollLine(dia, DDRR_TOLAYER, DiaGetCurLine(dia, DDRR_TOLAYER), pt);
2507 			continue;
2508 		}
2509 		if (itemHit == DDRR_CONDISTR || itemHit == DDRR_UCONDISTR ||
2510 			itemHit == DDRR_CONDISTWR || itemHit == DDRR_UCONDISTWR ||
2511 			itemHit == DDRR_CONDISTMR || itemHit == DDRR_UCONDISTMR ||
2512 			itemHit == DDRR_EDGEDISTR)
2513 		{
2514 			/* typed into rule field */
2515 			i = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2516 			if (i < 0) continue;
2517 			pt = DiaGetText(dia, itemHit);
2518 			layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2519 			if (layer1 < 0) continue;
2520 			layer2 = i;
2521 			if (layer1 > layer2) { temp = layer1; layer1 = layer2;  layer2 = temp; }
2522 			dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2523 			dindex = layer2 + rules->numlayers * layer1 - dindex;
2524 			if (itemHit == DDRR_CONDISTR)
2525 			{
2526 				if (estrcmp(rules->conlistR[dindex], pt) != 0) changed |= RULECHANGECONSPAR;
2527 				(void)reallocstring(&rules->conlistR[dindex], pt, el_tempcluster);
2528 			} else if (itemHit == DDRR_UCONDISTR)
2529 			{
2530 				if (estrcmp(rules->unconlistR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAR;
2531 				(void)reallocstring(&rules->unconlistR[dindex], pt, el_tempcluster);
2532 			} else if (itemHit == DDRR_CONDISTWR)
2533 			{
2534 				if (estrcmp(rules->conlistWR[dindex], pt) != 0) changed |= RULECHANGECONSPAWR;
2535 				(void)reallocstring(&rules->conlistWR[dindex], pt, el_tempcluster);
2536 			} else if (itemHit == DDRR_UCONDISTWR)
2537 			{
2538 				if (estrcmp(rules->unconlistWR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAWR;
2539 				(void)reallocstring(&rules->unconlistWR[dindex], pt, el_tempcluster);
2540 			} else if (itemHit == DDRR_CONDISTMR)
2541 			{
2542 				if (estrcmp(rules->conlistMR[dindex], pt) != 0) changed |= RULECHANGECONSPAMR;
2543 				(void)reallocstring(&rules->conlistMR[dindex], pt, el_tempcluster);
2544 			} else if (itemHit == DDRR_UCONDISTMR)
2545 			{
2546 				if (estrcmp(rules->unconlistMR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAMR;
2547 				(void)reallocstring(&rules->unconlistMR[dindex], pt, el_tempcluster);
2548 			} else if (itemHit == DDRR_EDGEDISTR)
2549 			{
2550 				if (estrcmp(rules->edgelistR[dindex], pt) != 0) changed |= RULECHANGEEDGESPAR;
2551 				(void)reallocstring(&rules->edgelistR[dindex], pt, el_tempcluster);
2552 			}
2553 			continue;
2554 		}
2555 		if (itemHit == DDRR_WIDELIMIT)
2556 		{
2557 			pt = DiaGetText(dia, DDRR_WIDELIMIT);
2558 			dist = atofr(pt);
2559 			if (rules->widelimit != dist) changed |= RULECHANGEWIDLIMIT;
2560 			rules->widelimit = dist;
2561 			continue;
2562 		}
2563 		if (itemHit == DDRR_MINWIDTH)
2564 		{
2565 			/* typed into min-width field */
2566 			pt = DiaGetText(dia, DDRR_MINWIDTH);
2567 			while (*pt == ' ' || *pt == '\t') pt++;
2568 			if (*pt == 0) dist = -WHOLE; else
2569 				dist = atofr(pt);
2570 			if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2571 			{
2572 				/* set the node minimum width */
2573 				i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2574 				if (rules->minnodesize[i*2] != dist) changed |= RULECHANGEMINSIZE;
2575 				rules->minnodesize[i*2] = dist;
2576 			} else
2577 			{
2578 				/* set the layer minimum width */
2579 				layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2580 				if (rules->minwidth[layer1] != dist) changed |= RULECHANGEMINWID;
2581 				rules->minwidth[layer1] = dist;
2582 			}
2583 			continue;
2584 		}
2585 		if (itemHit == DDRR_MINHEIGHT)
2586 		{
2587 			/* typed into min-width field */
2588 			pt = DiaGetText(dia, DDRR_MINHEIGHT);
2589 			while (*pt == ' ' || *pt == '\t') pt++;
2590 			if (*pt == 0) dist = -WHOLE; else
2591 				dist = atofr(pt);
2592 
2593 			/* set the node minimum height */
2594 			i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2595 			if (rules->minnodesize[i*2+1] != dist) changed |= RULECHANGEMINSIZE;
2596 			rules->minnodesize[i*2+1] = dist;
2597 			continue;
2598 		}
2599 		if (itemHit == DDRR_MINWIDTHR)
2600 		{
2601 			/* typed into min-width rule field */
2602 			pt = DiaGetText(dia, DDRR_MINWIDTHR);
2603 			while (*pt == ' ' || *pt == '\t') pt++;
2604 			if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2605 			{
2606 				/* set the node minimum width */
2607 				i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2608 				if (estrcmp(rules->minnodesizeR[i], pt) != 0) changed |= RULECHANGEMINSIZER;
2609 				(void)reallocstring(&rules->minnodesizeR[i], pt, el_tempcluster);
2610 			} else
2611 			{
2612 				/* set the layer minimum width */
2613 				layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2614 				if (estrcmp(rules->minwidthR[layer1], pt) != 0) changed |= RULECHANGEMINWIDR;
2615 				(void)reallocstring(&rules->minwidthR[layer1], pt, el_tempcluster);
2616 			}
2617 			continue;
2618 		}
2619 		if (itemHit == DDRR_FROMLAYER)
2620 		{
2621 			/* changed layer popup */
2622 			dr_loaddrcdialog(rules, validlayers, dia);
2623 			dr_loaddrcdistance(rules, dia);
2624 			continue;
2625 		}
2626 		if (itemHit == DDRR_TOLAYER)
2627 		{
2628 			/* clicked on new entry in scroll list of "to" layers */
2629 			dr_loaddrcdistance(rules, dia);
2630 			continue;
2631 		}
2632 		if (itemHit == DDRR_VALIDRULES)
2633 		{
2634 			DiaSetControl(dia, itemHit, 1-DiaGetControl(dia, itemHit));
2635 			dr_loaddrcdialog(rules, validlayers, dia);
2636 			dr_loaddrcdistance(rules, dia);
2637 			continue;
2638 		}
2639 	}
2640 
2641 	DiaDoneDialog(dia);
2642 
2643 	if (itemHit != OK) changed = 0;
2644 	if (itemHit == DDRR_FACTORYRST)
2645 	{
2646 		/* "factory reset" was clicked, start by deleting all DRC variables */
2647 		for(j=0; dr_variablenames[j] != 0; j++)
2648 		{
2649 			if (getval((INTBIG)tech, VTECHNOLOGY, -1, dr_variablenames[j]) == NOVARIABLE) continue;
2650 			(void)delval((INTBIG)tech, VTECHNOLOGY, dr_variablenames[j]);
2651 		}
2652 
2653 		/* set all technology-defined DRC variables */
2654 		for(i=0; tech->variables[i].name != 0; i++)
2655 		{
2656 			varname = tech->variables[i].name;
2657 			for(j=0; dr_variablenames[j] != 0; j++)
2658 				if (namesame(varname, dr_variablenames[j]) == 0) break;
2659 			if (dr_variablenames[j] == 0) continue;
2660 
2661 			/* reset the variable */
2662 			if (setval((INTBIG)tech, VTECHNOLOGY, tech->variables[i].name,
2663 				(INTBIG)tech->variables[i].value, tech->variables[i].type & ~VDONTSAVE) == NOVARIABLE) break;
2664 		}
2665 
2666 		/* call the technology-specific routine to do any extra work */
2667 		(void)asktech(tech, x_("factory-reset"));
2668 
2669 		/* also clear valid DRC dates */
2670 		dr_reset_dates();
2671 	}
2672 	efree((CHAR *)validlayers);
2673 	return(changed);
2674 }
2675 
dr_loaddrcruleobjects(DRCRULES * rules,INTBIG * validlayers,void * dia)2676 void dr_loaddrcruleobjects(DRCRULES *rules, INTBIG *validlayers, void *dia)
2677 {
2678 	REGISTER INTBIG i;
2679 
2680 	DiaLoadTextDialog(dia, DDRR_FROMLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);
2681 	if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2682 	{
2683 		/* list the nodes */
2684 		for(i=0; i<rules->numnodes; i++)
2685 			DiaStuffLine(dia, DDRR_FROMLAYER, rules->nodenames[i]);
2686 		DiaUnDimItem(dia, DDRR_MINHEIGHT_L);
2687 		DiaUnDimItem(dia, DDRR_MINHEIGHT);
2688 
2689 		DiaDimItem(dia, DDRR_CONDIST);
2690 		DiaDimItem(dia, DDRR_CONDISTR);
2691 		DiaDimItem(dia, DDRR_UCONDIST);
2692 		DiaDimItem(dia, DDRR_UCONDISTR);
2693 		DiaDimItem(dia, DDRR_CONDISTW);
2694 		DiaDimItem(dia, DDRR_CONDISTWR);
2695 		DiaDimItem(dia, DDRR_UCONDISTW);
2696 		DiaDimItem(dia, DDRR_UCONDISTWR);
2697 		DiaDimItem(dia, DDRR_CONDISTM);
2698 		DiaDimItem(dia, DDRR_CONDISTMR);
2699 		DiaDimItem(dia, DDRR_UCONDISTM);
2700 		DiaDimItem(dia, DDRR_UCONDISTMR);
2701 		DiaDimItem(dia, DDRR_WIDELIMIT);
2702 		DiaDimItem(dia, DDRR_EDGEDIST);
2703 		DiaDimItem(dia, DDRR_EDGEDISTR);
2704 		DiaDimItem(dia, DDRR_VALIDRULES);
2705 		DiaDimItem(dia, DDRR_NORMDIST_L);
2706 		DiaDimItem(dia, DDRR_CONDIST_L);
2707 		DiaDimItem(dia, DDRR_UCONDIST_L);
2708 		DiaDimItem(dia, DDRR_EDGEDIST_L);
2709 		DiaDimItem(dia, DDRR_WIDEDIST_L);
2710 		DiaDimItem(dia, DDRR_CONDISTW_L);
2711 		DiaDimItem(dia, DDRR_UCONDISTW_L);
2712 		DiaDimItem(dia, DDRR_MULTIDIST_L);
2713 		DiaDimItem(dia, DDRR_CONDISTM_L);
2714 		DiaDimItem(dia, DDRR_UCONDISTM_L);
2715 		DiaDimItem(dia, DDRR_DIST_L);
2716 		DiaDimItem(dia, DDRR_DISTR_L);
2717 		DiaDimItem(dia, DDRR_TOLAYER_L);
2718 		DiaDimItem(dia, DDRR_TOLAYER);
2719 	} else
2720 	{
2721 		/* list the layers */
2722 		for(i=0; i<rules->numlayers; i++)
2723 		{
2724 			if (validlayers[i] == 0) continue;
2725 			DiaStuffLine(dia, DDRR_FROMLAYER, rules->layernames[i]);
2726 		}
2727 		DiaDimItem(dia, DDRR_MINHEIGHT_L);
2728 		DiaDimItem(dia, DDRR_MINHEIGHT);
2729 
2730 		DiaUnDimItem(dia, DDRR_CONDIST);
2731 		DiaUnDimItem(dia, DDRR_CONDISTR);
2732 		DiaUnDimItem(dia, DDRR_UCONDIST);
2733 		DiaUnDimItem(dia, DDRR_UCONDISTR);
2734 		DiaUnDimItem(dia, DDRR_CONDISTW);
2735 		DiaUnDimItem(dia, DDRR_CONDISTWR);
2736 		DiaUnDimItem(dia, DDRR_UCONDISTW);
2737 		DiaUnDimItem(dia, DDRR_UCONDISTWR);
2738 		DiaUnDimItem(dia, DDRR_CONDISTM);
2739 		DiaUnDimItem(dia, DDRR_CONDISTMR);
2740 		DiaUnDimItem(dia, DDRR_UCONDISTM);
2741 		DiaUnDimItem(dia, DDRR_UCONDISTMR);
2742 		DiaUnDimItem(dia, DDRR_WIDELIMIT);
2743 		DiaUnDimItem(dia, DDRR_EDGEDIST);
2744 		DiaUnDimItem(dia, DDRR_EDGEDISTR);
2745 		DiaUnDimItem(dia, DDRR_VALIDRULES);
2746 		DiaUnDimItem(dia, DDRR_NORMDIST_L);
2747 		DiaUnDimItem(dia, DDRR_CONDIST_L);
2748 		DiaUnDimItem(dia, DDRR_UCONDIST_L);
2749 		DiaUnDimItem(dia, DDRR_EDGEDIST_L);
2750 		DiaUnDimItem(dia, DDRR_WIDEDIST_L);
2751 		DiaUnDimItem(dia, DDRR_CONDISTW_L);
2752 		DiaUnDimItem(dia, DDRR_UCONDISTW_L);
2753 		DiaUnDimItem(dia, DDRR_MULTIDIST_L);
2754 		DiaUnDimItem(dia, DDRR_CONDISTM_L);
2755 		DiaUnDimItem(dia, DDRR_UCONDISTM_L);
2756 		DiaUnDimItem(dia, DDRR_DIST_L);
2757 		DiaUnDimItem(dia, DDRR_DISTR_L);
2758 		DiaUnDimItem(dia, DDRR_TOLAYER_L);
2759 		DiaUnDimItem(dia, DDRR_TOLAYER);
2760 	}
2761 	DiaSelectLine(dia, DDRR_FROMLAYER, 0);
2762 }
2763 
2764 /*
2765  * Routine to show the detail on the selected layer/node in the upper scroll area.
2766  */
dr_loaddrcdialog(DRCRULES * rules,INTBIG * validlayers,void * dia)2767 void dr_loaddrcdialog(DRCRULES *rules, INTBIG *validlayers, void *dia)
2768 {
2769 	REGISTER INTBIG i, j, layer1, layer2, temp, dindex, onlyvalid, count;
2770 	REGISTER CHAR *line;
2771 
2772 	if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2773 	{
2774 		/* show node information */
2775 		j = DiaGetCurLine(dia, DDRR_FROMLAYER);
2776 		if (j < 0) return;
2777 		DiaSetText(dia, DDRR_MINWIDTH, frtoa(rules->minnodesize[j*2]));
2778 		DiaSetText(dia, DDRR_MINHEIGHT, frtoa(rules->minnodesize[j*2+1]));
2779 		DiaSetText(dia, DDRR_MINWIDTHR, rules->minnodesizeR[j]);
2780 	} else
2781 	{
2782 		/* show layer information */
2783 		onlyvalid = DiaGetControl(dia, DDRR_VALIDRULES);
2784 		j = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2785 		if (rules->minwidth[j] < 0) DiaSetText(dia, DDRR_MINWIDTH, x_("")); else
2786 			DiaSetText(dia, DDRR_MINWIDTH, frtoa(rules->minwidth[j]));
2787 		DiaSetText(dia, DDRR_MINWIDTHR, rules->minwidthR[j]);
2788 		DiaLoadTextDialog(dia, DDRR_TOLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);
2789 		count = 0;
2790 		for(i=0; i<rules->numlayers; i++)
2791 		{
2792 			if (validlayers[i] == 0) continue;
2793 			layer1 = j;
2794 			layer2 = i;
2795 			if (layer1 > layer2) { temp = layer1; layer1 = layer2;  layer2 = temp; }
2796 			dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2797 			dindex = layer2 + rules->numlayers * layer1 - dindex;
2798 
2799 			line = dr_loadoptlistline(rules, dindex, i, onlyvalid);
2800 			if (*line == 0) continue;
2801 			DiaStuffLine(dia, DDRR_TOLAYER, line);
2802 			count++;
2803 		}
2804 		if (count > 0) DiaSelectLine(dia, DDRR_TOLAYER, 0);
2805 	}
2806 }
2807 
dr_loadoptlistline(DRCRULES * rules,INTBIG dindex,INTBIG lindex,INTBIG onlyvalid)2808 CHAR *dr_loadoptlistline(DRCRULES *rules, INTBIG dindex, INTBIG lindex, INTBIG onlyvalid)
2809 {
2810 	REGISTER CHAR *condist, *uncondist, *wcondist, *wuncondist,
2811 		*mcondist, *muncondist, *edgedist;
2812 	REGISTER void *infstr;
2813 
2814 	if (rules->conlist[dindex] < 0) condist = x_(""); else
2815 		condist = frtoa(rules->conlist[dindex]);
2816 	if (rules->unconlist[dindex] < 0) uncondist = x_(""); else
2817 		uncondist = frtoa(rules->unconlist[dindex]);
2818 	if (rules->conlistW[dindex] < 0) wcondist = x_(""); else
2819 		wcondist = frtoa(rules->conlistW[dindex]);
2820 	if (rules->unconlistW[dindex] < 0) wuncondist = x_(""); else
2821 		wuncondist = frtoa(rules->unconlistW[dindex]);
2822 	if (rules->conlistM[dindex] < 0) mcondist = x_(""); else
2823 		mcondist = frtoa(rules->conlistM[dindex]);
2824 	if (rules->unconlistM[dindex] < 0) muncondist = x_(""); else
2825 		muncondist = frtoa(rules->unconlistM[dindex]);
2826 	if (rules->edgelist[dindex] < 0) edgedist = x_(""); else
2827 		edgedist = frtoa(rules->edgelist[dindex]);
2828 	if (onlyvalid != 0)
2829 	{
2830 		if (*condist == 0 && *uncondist == 0 && *wcondist == 0 &&
2831 			*wuncondist == 0 && *mcondist == 0 && *muncondist == 0 &&
2832 			*edgedist == 0) return(x_(""));
2833 	}
2834 	infstr = initinfstr();
2835 	formatinfstr(infstr, x_("%s (%s/%s/%s/%s/%s/%s/%s)"), rules->layernames[lindex],
2836 		condist, uncondist, wcondist, wuncondist, mcondist, muncondist, edgedist);
2837 	return(returninfstr(infstr));
2838 }
2839 
dr_rulesdialoggetlayer(DRCRULES * rules,INTBIG item,void * dia)2840 INTBIG dr_rulesdialoggetlayer(DRCRULES *rules, INTBIG item, void *dia)
2841 {
2842 	REGISTER INTBIG i, layer;
2843 	REGISTER CHAR *lname, save, *endpos;
2844 
2845 	i = DiaGetCurLine(dia, item);
2846 	if (i < 0) return(-1);
2847 	lname = DiaGetScrollLine(dia, item, i);
2848 	for(endpos = lname; *endpos != 0; endpos++)
2849 		if (endpos[0] == ' ' && endpos[1] == '(') break;
2850 	save = *endpos;
2851 	*endpos = 0;
2852 	for(layer=0; layer<rules->numlayers; layer++)
2853 		if (namesame(lname, rules->layernames[layer]) == 0) break;
2854 	*endpos = save;
2855 	if (layer >= rules->numlayers) return(-1);
2856 	return(layer);
2857 }
2858 
dr_loaddrcdistance(DRCRULES * rules,void * dia)2859 void dr_loaddrcdistance(DRCRULES *rules, void *dia)
2860 {
2861 	REGISTER INTBIG layer1, layer2, temp, dindex;
2862 
2863 	if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2864 	{
2865 		/* show node information */
2866 	} else
2867 	{
2868 		/* show layer information */
2869 		DiaSetText(dia, DDRR_CONDIST, x_(""));    DiaSetText(dia, DDRR_CONDISTR, x_(""));
2870 		DiaSetText(dia, DDRR_UCONDIST, x_(""));   DiaSetText(dia, DDRR_UCONDISTR, x_(""));
2871 		DiaSetText(dia, DDRR_CONDISTW, x_(""));   DiaSetText(dia, DDRR_CONDISTWR, x_(""));
2872 		DiaSetText(dia, DDRR_UCONDISTW, x_(""));  DiaSetText(dia, DDRR_UCONDISTWR, x_(""));
2873 		DiaSetText(dia, DDRR_CONDISTM, x_(""));   DiaSetText(dia, DDRR_CONDISTMR, x_(""));
2874 		DiaSetText(dia, DDRR_UCONDISTM, x_(""));  DiaSetText(dia, DDRR_UCONDISTMR, x_(""));
2875 		DiaSetText(dia, DDRR_EDGEDIST, x_(""));   DiaSetText(dia, DDRR_EDGEDISTR, x_(""));
2876 
2877 		layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2878 		if (layer1 < 0) return;
2879 		layer2 = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2880 		if (layer2 < 0) return;
2881 
2882 		if (layer1 > layer2) { temp = layer1; layer1 = layer2;  layer2 = temp; }
2883 		dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2884 		dindex = layer2 + rules->numlayers * layer1 - dindex;
2885 
2886 		if (rules->conlist[dindex] >= 0)
2887 			DiaSetText(dia, DDRR_CONDIST, frtoa(rules->conlist[dindex]));
2888 		if (rules->unconlist[dindex] >= 0)
2889 			DiaSetText(dia, DDRR_UCONDIST, frtoa(rules->unconlist[dindex]));
2890 		if (rules->conlistW[dindex] >= 0)
2891 			DiaSetText(dia, DDRR_CONDISTW, frtoa(rules->conlistW[dindex]));
2892 		if (rules->unconlistW[dindex] >= 0)
2893 			DiaSetText(dia, DDRR_UCONDISTW, frtoa(rules->unconlistW[dindex]));
2894 		if (rules->conlistM[dindex] >= 0)
2895 			DiaSetText(dia, DDRR_CONDISTM, frtoa(rules->conlistM[dindex]));
2896 		if (rules->unconlistM[dindex] >= 0)
2897 			DiaSetText(dia, DDRR_UCONDISTM, frtoa(rules->unconlistM[dindex]));
2898 		if (rules->edgelist[dindex] >= 0)
2899 			DiaSetText(dia, DDRR_EDGEDIST, frtoa(rules->edgelist[dindex]));
2900 
2901 		DiaSetText(dia, DDRR_CONDISTR, rules->conlistR[dindex]);
2902 		DiaSetText(dia, DDRR_UCONDISTR, rules->unconlistR[dindex]);
2903 		DiaSetText(dia, DDRR_CONDISTWR, rules->conlistWR[dindex]);
2904 		DiaSetText(dia, DDRR_UCONDISTWR, rules->unconlistWR[dindex]);
2905 		DiaSetText(dia, DDRR_CONDISTMR, rules->conlistMR[dindex]);
2906 		DiaSetText(dia, DDRR_UCONDISTMR, rules->unconlistMR[dindex]);
2907 		DiaSetText(dia, DDRR_EDGEDISTR, rules->edgelistR[dindex]);
2908 	}
2909 }
2910 
2911 #endif  /* DRCTOOL - at top */
2912