1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usredtecp.c
6  * User interface technology editor: conversion from library to technology
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 "global.h"
33 #include "egraphics.h"
34 #include "efunction.h"
35 #include "tech.h"
36 #include "tecgen.h"
37 #include "tecart.h"
38 #include "usr.h"
39 #include "drc.h"
40 #include "usredtec.h"
41 
42 /* the globals that define a technology */
43 static INTBIG           us_tecflags;
44 static INTBIG           us_teclayer_count;
45 static CHAR           **us_teclayer_iname = 0;
46 static CHAR           **us_teclayer_names = 0;
47 static CHAR           **us_teccif_layers = 0;
48 static CHAR           **us_tecdxf_layers = 0;
49 static CHAR           **us_tecgds_layers = 0;
50 static INTBIG          *us_teclayer_function = 0;
51 static CHAR           **us_teclayer_letters = 0;
52 static DRCRULES        *us_tecdrc_rules = 0;
53 static float           *us_tecspice_res = 0;
54 static float           *us_tecspice_cap = 0;
55 static float           *us_tecspice_ecap = 0;
56 static INTBIG          *us_tec3d_height = 0;
57 static INTBIG          *us_tec3d_thickness = 0;
58 static INTBIG          *us_tecprint_colors = 0;
59 static INTBIG           us_tecarc_count;
60 static INTBIG          *us_tecarc_widoff = 0;
61 static INTBIG           us_tecnode_count;
62 static INTBIG          *us_tecnode_widoff = 0;
63 static INTBIG          *us_tecnode_grab = 0;
64 static INTBIG           us_tecnode_grabcount;
65 static TECH_COLORMAP    us_teccolmap[32];
66 
67 static PCON  *us_tecedfirstpcon = NOPCON;	/* list of port connections */
68 static RULE  *us_tecedfirstrule = NORULE;	/* list of rules */
69 
70 /* working memory for "us_tecedmakeprim()" */
71 static INTBIG *us_tecedmakepx, *us_tecedmakepy, *us_tecedmakefactor,
72 	*us_tecedmakeleftdist, *us_tecedmakerightdist, *us_tecedmakebotdist,
73 	*us_tecedmaketopdist, *us_tecedmakecentxdist, *us_tecedmakecentydist, *us_tecedmakeratiox,
74 	*us_tecedmakeratioy, *us_tecedmakecx, *us_tecedmakecy;
75 static INTBIG us_tecedmakearrlen = 0;
76 
77 /* working memory for "us_teceditgetdependents()" */
78 static LIBRARY **us_teceddepliblist;
79 static INTBIG    us_teceddepliblistsize = 0;
80 
81 /* prototypes for local routines */
82 static void     us_tecedcheck(TECHNOLOGY*);
83 static BOOLEAN  us_tecedmakefactors(LIBRARY**, INTBIG, TECHNOLOGY*);
84 static BOOLEAN  us_tecedmakelayers(LIBRARY**, INTBIG, TECHNOLOGY*);
85 static BOOLEAN  us_tecedmakearcs(LIBRARY**, INTBIG, TECHNOLOGY*);
86 static BOOLEAN  us_tecedmakenodes(LIBRARY**, INTBIG, TECHNOLOGY*);
87 static INTBIG   us_tecedfindport(TECH_NODES*, EXAMPLE*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
88 static BOOLEAN  us_tecedassociateexamples(EXAMPLE*, NODEPROTO*);
89 static BOOLEAN  us_tecedmakeprim(EXAMPLE*, NODEPROTO*, TECHNOLOGY*, TECH_NODES*, INTBIG);
90 static void     us_tecedforcearrays(INTBIG);
91 static INTBIG  *us_tecedstretchpoints(INTBIG*, INTBIG*, INTBIG, INTBIG*, SAMPLE*, NODEPROTO*, EXAMPLE*);
92 static BOOLEAN  us_tecedmulticut(SAMPLE*, EXAMPLE*, NODEPROTO*);
93 static PCON    *us_tecedaddportlist(INTBIG, INTBIG*);
94 static CHAR    *us_tecedmakesymbol(CHAR*);
95 static CHAR    *us_tecedmakefract(INTBIG);
96 static void     us_teceditdumpdrctab(FILE*, void*, TECHNOLOGY*, BOOLEAN);
97 static CHAR    *us_tecedmakeupper(CHAR*);
98 static CHAR    *us_tecededgelabel(INTBIG, INTBIG, BOOLEAN);
99 static void     us_tecedfreetechmemory(void);
100 static RULE    *us_tecedaddrule(INTBIG list[8], INTBIG count, BOOLEAN multcut, CHAR *istext);
101 static int      us_samplecoordascending(const void *e1, const void *e2);
102 static void     us_teceditdumplayers(FILE *f, TECHNOLOGY *tech, CHAR *techname);
103 static void     us_teceditdumparcs(FILE *f, TECHNOLOGY *tech, CHAR *techname);
104 static void     us_teceditdumpnodes(FILE *f, TECHNOLOGY *tech, CHAR *techname);
105 static void     us_teceditdumpvars(FILE *f, TECHNOLOGY *tech, CHAR *techname);
106 static CHAR    *us_tecedmakefloatstring(float v);
107 static RULE    *us_tecedaddmulticutrule(INTBIG multixs, INTBIG multiys, INTBIG multiindent, INTBIG multisep);
108 static SAMPLE  *us_tecedneedhighlightlayer(EXAMPLE *nelist, NODEPROTO *np);
109 static CHAR    *us_teceditgetparameter(VARIABLE *var);
110 static void     us_teceditdumpjavalayers(FILE *f, TECHNOLOGY *tech, CHAR *techname);
111 static void     us_teceditdumpjavadrctab(FILE *f, void *distances, TECHNOLOGY *tech, BOOLEAN isstring);
112 static void     us_teceditdumpjavaarcs(FILE *f, TECHNOLOGY *tech, CHAR *techname);
113 static void     us_teceditdumpjavanodes(FILE *f, TECHNOLOGY *tech, CHAR *techname);
114 static CHAR    *us_tecededgelabeljava(INTBIG mul, INTBIG add, BOOLEAN yaxis);
115 static CHAR    *us_teceditconverttojava(CHAR *string);
116 
117 /*
118  * Routine to free all memory associated with this module.
119  */
us_freeedtecpmemory(void)120 void us_freeedtecpmemory(void)
121 {
122 	if (us_tecedmakearrlen != 0)
123 	{
124 		efree((CHAR *)us_tecedmakepx);
125 		efree((CHAR *)us_tecedmakepy);
126 		efree((CHAR *)us_tecedmakecx);
127 		efree((CHAR *)us_tecedmakecy);
128 		efree((CHAR *)us_tecedmakefactor);
129 		efree((CHAR *)us_tecedmakeleftdist);
130 		efree((CHAR *)us_tecedmakerightdist);
131 		efree((CHAR *)us_tecedmakebotdist);
132 		efree((CHAR *)us_tecedmaketopdist);
133 		efree((CHAR *)us_tecedmakecentxdist);
134 		efree((CHAR *)us_tecedmakecentydist);
135 		efree((CHAR *)us_tecedmakeratiox);
136 		efree((CHAR *)us_tecedmakeratioy);
137 	}
138 	if (us_teceddepliblistsize != 0) efree((CHAR *)us_teceddepliblist);
139 	us_tecedfreetechmemory();
140 }
141 
142 /*
143  * the routine invoked for the "technology edit library-to-tech" command.  Dumps
144  * C code if "dumpc" is nonzero
145  */
us_tecfromlibinit(LIBRARY * lib,CHAR * techname,INTBIG dumpformat)146 void us_tecfromlibinit(LIBRARY *lib, CHAR *techname, INTBIG dumpformat)
147 {
148 	REGISTER FILE *f;
149 	REGISTER TECHNOLOGY *tech;
150 	REGISTER CLUSTER *clus;
151 	REGISTER VARIABLE *var, *ovar;
152 	REGISTER CHAR **varnames;
153 	CHAR *truename, *newtechname;
154 	LIBRARY **dependentlibs;
155 	REGISTER INTBIG dependentlibcount, i, j, modified;
156 	REGISTER void *infstr;
157 	static TECH_VARIABLES us_tecvariables[2] = {{NULL, NULL, 0.0, 0},
158                                                 {NULL, NULL, 0.0, 0}};
159 
160 	/* make sure network tool is on */
161 	if ((net_tool->toolstate&TOOLON) == 0)
162 	{
163 		ttyputerr(_("Network tool must be running...turning it on"));
164 		toolturnon(net_tool);
165 		ttyputerr(_("...now reissue the technology editing command"));
166 		return;
167 	}
168 
169 	/* loop until the name is valid */
170 	if (techname == 0) techname = lib->libname;
171 	if (allocstring(&newtechname, techname, el_tempcluster)) return;
172 	modified = 0;
173 	for(;;)
174 	{
175 		/* search by hand because "gettechnology" handles partial matches */
176 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
177 			if (namesame(newtechname, tech->techname) == 0) break;
178 		if (tech == NOTECHNOLOGY) break;
179 		infstr = initinfstr();
180 		addstringtoinfstr(infstr, newtechname);
181 		addtoinfstr(infstr, 'X');
182 		(void)reallocstring(&newtechname, returninfstr(infstr), el_tempcluster);
183 		modified= 1;
184 	}
185 
186 	/* create the technology */
187 	infstr = initinfstr();
188 	addstringtoinfstr(infstr, x_("tech:"));
189 	addstringtoinfstr(infstr, newtechname);
190 	clus = alloccluster(returninfstr(infstr));
191 	if (clus == NOCLUSTER) return;
192 	tech = alloctechnology(clus);
193 	if (tech == NOTECHNOLOGY) return;
194 
195 	/* set the technology name */
196 	if (allocstring(&tech->techname, newtechname, clus)) return;
197 	efree((CHAR *)newtechname);
198 	if (modified != 0)
199 		ttyputmsg(_("Warning: already a technology called %s.  Naming this %s"),
200 			techname, tech->techname);
201 
202 	/* set technology description */
203 	if (allocstring(&tech->techdescript, tech->techname, clus)) return;
204 
205 	/* free any previous memory for the technology */
206 	us_tecedfreetechmemory();
207 
208 	/* get list of dependent libraries */
209 	dependentlibcount = us_teceditgetdependents(lib, &dependentlibs);
210 
211 	/* initialize the state of this technology */
212 	us_tecflags = 0;
213 	if (us_tecedmakefactors(dependentlibs, dependentlibcount, tech)) return;
214 
215 	/* build layer structures */
216 	if (us_tecedmakelayers(dependentlibs, dependentlibcount, tech)) return;
217 
218 	/* build arc structures */
219 	if (us_tecedmakearcs(dependentlibs, dependentlibcount, tech)) return;
220 
221 	/* build node structures */
222 	if (us_tecedmakenodes(dependentlibs, dependentlibcount, tech)) return;
223 
224 	/* copy any miscellaneous variables (should use dependent libraries facility) */
225 	var = getval((INTBIG)lib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_variable_list"));
226 	if (var != NOVARIABLE)
227 	{
228 		j = getlength(var);
229 		varnames = (CHAR **)var->addr;
230 		for(i=0; i<j; i++)
231 		{
232 			ovar = getval((INTBIG)lib, VLIBRARY, -1, varnames[i]);
233 			if (ovar == NOVARIABLE) continue;
234 			(void)setval((INTBIG)tech, VTECHNOLOGY, varnames[i], ovar->addr, ovar->type);
235 		}
236 	}
237 
238 	/* check technology for consistency */
239 	us_tecedcheck(tech);
240 
241 	if (dumpformat > 0)
242 	{
243 		/* print the technology as C code */
244 		infstr = initinfstr();
245 		addstringtoinfstr(infstr, x_("tec"));
246 		addstringtoinfstr(infstr, techname);
247 		addstringtoinfstr(infstr, x_(".c"));
248 		f = xcreate(returninfstr(infstr), el_filetypetext, _("Technology Code File"), &truename);
249 		if (f == NULL)
250 		{
251 			if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
252 			return;
253 		}
254 		ttyputverbose(M_("Writing: %s"), truename);
255 
256 		/* write the layers, arcs, and nodes */
257 		us_teceditdumplayers(f, tech, techname);
258 		us_teceditdumparcs(f, tech, techname);
259 		us_teceditdumpnodes(f, tech, techname);
260 		us_teceditdumpvars(f, tech, techname);
261 
262 		/* clean up */
263 		xclose(f);
264 	}
265 
266 	if (dumpformat < 0)
267 	{
268 		/* print the technology as Java code */
269 		infstr = initinfstr();
270 		addstringtoinfstr(infstr, techname);
271 		addstringtoinfstr(infstr, x_(".java"));
272 		f = xcreate(returninfstr(infstr), el_filetypetext, _("Technology Code File"), &truename);
273 		if (f == NULL)
274 		{
275 			if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
276 			return;
277 		}
278 		ttyputverbose(M_("Writing: %s"), truename);
279 
280 		/* write the layers, arcs, and nodes */
281 		us_teceditdumpjavalayers(f, tech, techname);
282 		us_teceditdumpjavaarcs(f, tech, techname);
283 		us_teceditdumpjavanodes(f, tech, techname);
284 		xprintf(f, x_("}\n"));
285 
286 		/* clean up */
287 		xclose(f);
288 	}
289 
290 	/* finish initializing the technology */
291 	if ((us_tecflags&HASGRAB) == 0) us_tecvariables[0].name = 0; else
292 	{
293 		us_tecvariables[0].name = x_("prototype_center");
294 		us_tecvariables[0].value = (CHAR *)us_tecnode_grab;
295 		us_tecvariables[0].type = us_tecnode_grabcount/3;
296 	}
297 	tech->variables = us_tecvariables;
298 	if (tech_doinitprocess(tech)) return;
299 	if (tech_doaddportsandvars(tech)) return;
300 
301 	/* install the technology fully */
302 	addtechnology(tech);
303 
304 	/* let the user interface process it */
305 	us_figuretechopaque(tech);
306 
307 	/* switch to this technology */
308 	ttyputmsg(_("Technology %s built.  Switching to it."), tech->techname);
309 	us_setnodeproto(NONODEPROTO);
310 	us_setarcproto(NOARCPROTO, TRUE);
311 
312 	/* disable option tracking while colormap is updated */
313 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey, 1,
314 		VINTEGER|VDONTSAVE);
315 	us_getcolormap(tech, COLORSEXISTING, TRUE);
316 	var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_ignoreoptionchangeskey);
317 	if (var != NOVARIABLE)
318 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey);
319 
320 	(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_technology_key, (INTBIG)tech,
321 		VTECHNOLOGY|VDONTSAVE);
322 
323 	/* fix up the menu entries */
324 	us_setmenunodearcs();
325 	if ((us_state&NONPERSISTENTCURNODE) == 0) us_setnodeproto(tech->firstnodeproto);
326 	us_setarcproto(tech->firstarcproto, TRUE);
327 }
328 
us_tecedcheck(TECHNOLOGY * tech)329 void us_tecedcheck(TECHNOLOGY *tech)
330 {
331 	REGISTER INTBIG i, j, k, l;
332 	REGISTER TECH_POLYGON *plist;
333 	REGISTER TECH_NODES *nlist;
334 
335 	/* make sure there is a pure-layer node for every nonpseudo layer */
336 	for(i=0; i<tech->layercount; i++)
337 	{
338 		if ((us_teclayer_function[i]&LFPSEUDO) != 0) continue;
339 		for(j=0; j<tech->nodeprotocount; j++)
340 		{
341 			nlist = tech->nodeprotos[j];
342 			if (((nlist->initialbits&NFUNCTION)>>NFUNCTIONSH) != NPNODE) continue;
343 			plist = &nlist->layerlist[0];
344 			if (plist->layernum == i) break;
345 		}
346 		if (j < tech->nodeprotocount) continue;
347 		ttyputmsg(_("Warning: Layer %s has no associated pure-layer node"),
348 			us_teclayer_names[i]);
349 	}
350 
351 	/* make sure there is a pin for every arc and that it uses pseudo-layers */
352 	for(i=0; i<tech->arcprotocount; i++)
353 	{
354 		for(j=0; j<tech->nodeprotocount; j++)
355 		{
356 			nlist = tech->nodeprotos[j];
357 			if (((nlist->initialbits&NFUNCTION)>>NFUNCTIONSH) != NPPIN) continue;
358 			for(k=0; k<nlist->portcount; k++)
359 			{
360 				for(l=1; nlist->portlist[k].portarcs[l] >= 0; l++)
361 					if (nlist->portlist[k].portarcs[l] == i) break;
362 				if (nlist->portlist[k].portarcs[l] >= 0) break;
363 			}
364 			if (k < nlist->portcount) break;
365 		}
366 		if (j < tech->nodeprotocount)
367 		{
368 			/* pin found: make sure it uses pseudo-layers */
369 			nlist = tech->nodeprotos[j];
370 			for(k=0; k<nlist->layercount; k++)
371 			{
372 				plist = &nlist->layerlist[k];
373 				if ((us_teclayer_function[plist->layernum]&LFPSEUDO) == 0) break;
374 			}
375 			if (k < nlist->layercount)
376 				ttyputmsg(_("Warning: Pin %s is not composed of pseudo-layers"),
377 					tech->nodeprotos[j]->nodename);
378 			continue;
379 		}
380 		ttyputmsg(_("Warning: Arc %s has no associated pin node"), tech->arcprotos[i]->arcname);
381 	}
382 }
383 
us_tecedfreetechmemory(void)384 void us_tecedfreetechmemory(void)
385 {
386 	REGISTER INTBIG i;
387 	REGISTER PCON *pc;
388 	REGISTER RULE *r;
389 
390 	/* free DRC layer name information */
391 	if (us_teceddrclayernames != 0)
392 	{
393 		for(i=0; i<us_teceddrclayers; i++) efree(us_teceddrclayernames[i]);
394 		efree((CHAR *)us_teceddrclayernames);
395 		us_teceddrclayernames = 0;
396 	}
397 
398 	if (us_teclayer_iname != 0)
399 	{
400 		for(i=0; i<us_teclayer_count; i++)
401 			if (us_teclayer_iname[i] != 0) efree((CHAR *)us_teclayer_iname[i]);
402 		efree((CHAR *)us_teclayer_iname);
403 		us_teclayer_iname = 0;
404 	}
405 	if (us_teclayer_names != 0)
406 	{
407 		for(i=0; i<us_teclayer_count; i++)
408 			if (us_teclayer_names[i] != 0) efree((CHAR *)us_teclayer_names[i]);
409 		efree((CHAR *)us_teclayer_names);
410 		us_teclayer_names = 0;
411 	}
412 	if (us_teccif_layers != 0)
413 	{
414 		for(i=0; i<us_teclayer_count; i++)
415 			if (us_teccif_layers[i] != 0) efree((CHAR *)us_teccif_layers[i]);
416 		efree((CHAR *)us_teccif_layers);
417 		us_teccif_layers = 0;
418 	}
419 	if (us_tecdxf_layers != 0)
420 	{
421 		for(i=0; i<us_teclayer_count; i++)
422 			if (us_tecdxf_layers[i] != 0) efree((CHAR *)us_tecdxf_layers[i]);
423 		efree((CHAR *)us_tecdxf_layers);
424 		us_tecdxf_layers = 0;
425 	}
426 	if (us_tecgds_layers != 0)
427 	{
428 		for(i=0; i<us_teclayer_count; i++)
429 			if (us_tecgds_layers[i] != 0) efree((CHAR *)us_tecgds_layers[i]);
430 		efree((CHAR *)us_tecgds_layers);
431 		us_tecgds_layers = 0;
432 	}
433 	if (us_teclayer_function != 0)
434 	{
435 		efree((CHAR *)us_teclayer_function);
436 		us_teclayer_function = 0;
437 	}
438 	if (us_teclayer_letters != 0)
439 	{
440 		for(i=0; i<us_teclayer_count; i++)
441 			if (us_teclayer_letters[i] != 0) efree((CHAR *)us_teclayer_letters[i]);
442 		efree((CHAR *)us_teclayer_letters);
443 		us_teclayer_letters = 0;
444 	}
445 	if (us_tecdrc_rules != 0)
446 	{
447 		dr_freerules(us_tecdrc_rules);
448 		us_tecdrc_rules = 0;
449 	}
450 	if (us_tecspice_res != 0)
451 	{
452 		efree((CHAR *)us_tecspice_res);
453 		us_tecspice_res = 0;
454 	}
455 	if (us_tecspice_cap != 0)
456 	{
457 		efree((CHAR *)us_tecspice_cap);
458 		us_tecspice_cap = 0;
459 	}
460 	if (us_tecspice_ecap != 0)
461 	{
462 		efree((CHAR *)us_tecspice_ecap);
463 		us_tecspice_ecap = 0;
464 	}
465 	if (us_tec3d_height != 0)
466 	{
467 		efree((CHAR *)us_tec3d_height);
468 		us_tec3d_height = 0;
469 	}
470 	if (us_tec3d_thickness != 0)
471 	{
472 		efree((CHAR *)us_tec3d_thickness);
473 		us_tec3d_thickness = 0;
474 	}
475 	if (us_tecprint_colors != 0)
476 	{
477 		efree((CHAR *)us_tecprint_colors);
478 		us_tecprint_colors = 0;
479 	}
480 
481 	if (us_tecarc_widoff != 0)
482 	{
483 		efree((CHAR *)us_tecarc_widoff);
484 		us_tecarc_widoff = 0;
485 	}
486 
487 	if (us_tecnode_widoff != 0)
488 	{
489 		efree((CHAR *)us_tecnode_widoff);
490 		us_tecnode_widoff = 0;
491 	}
492 	if (us_tecnode_grab != 0)
493 	{
494 		efree((CHAR *)us_tecnode_grab);
495 		us_tecnode_grab = 0;
496 	}
497 
498 	while (us_tecedfirstpcon != NOPCON)
499 	{
500 		pc = us_tecedfirstpcon;
501 		us_tecedfirstpcon = us_tecedfirstpcon->nextpcon;
502 		efree((CHAR *)pc->connects);
503 		efree((CHAR *)pc->assoc);
504 		efree((CHAR *)pc);
505 	}
506 
507 	while (us_tecedfirstrule != NORULE)
508 	{
509 		r = us_tecedfirstrule;
510 		us_tecedfirstrule = us_tecedfirstrule->nextrule;
511 		efree((CHAR *)r->value);
512 		efree((CHAR *)r);
513 	}
514 }
515 
516 /*
517  * routine to scan the "dependentlibcount" libraries in "dependentlibs",
518  * and get global factors for technology "tech".  Returns true on error.
519  */
us_tecedmakefactors(LIBRARY ** dependentlibs,INTBIG dependentlibcount,TECHNOLOGY * tech)520 BOOLEAN us_tecedmakefactors(LIBRARY **dependentlibs, INTBIG dependentlibcount, TECHNOLOGY *tech)
521 {
522 	REGISTER NODEPROTO *np;
523 	REGISTER NODEINST *ni;
524 	REGISTER VARIABLE *var;
525 	REGISTER INTBIG opt;
526 	REGISTER CHAR *str;
527 	REGISTER INTBIG i;
528 
529 	np = NONODEPROTO;
530 	for(i=dependentlibcount-1; i>=0; i--)
531 	{
532 		for(np = dependentlibs[i]->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
533 			if (namesame(np->protoname, x_("factors")) == 0) break;
534 		if (np != NONODEPROTO) break;
535 	}
536 	if (np == NONODEPROTO)
537 	{
538 		tech->deflambda = 2000;
539 		return(FALSE);
540 	}
541 
542 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
543 	{
544 		opt = us_tecedgetoption(ni);
545 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
546 		if (var == NOVARIABLE) continue;
547 		str = (CHAR *)var->addr;
548 		switch (opt)
549 		{
550 			case TECHLAMBDA:	/* lambda */
551 				tech->deflambda = myatoi(&str[8]);
552 				break;
553 			case TECHDESCRIPT:	/* description */
554 				(void)reallocstring(&tech->techdescript, &str[13], tech->cluster);
555 				break;
556 			default:
557 				us_tecedpointout(ni, np);
558 				ttyputerr(_("Unknown object in miscellaneous-information cell"));
559 				return(TRUE);
560 		}
561 	}
562 	return(FALSE);
563 }
564 
565 /*
566  * routine to scan the "dependentlibcount" libraries in "dependentlibs",
567  * and build the layer structures for it in technology "tech".  Returns true on error.
568  */
us_tecedmakelayers(LIBRARY ** dependentlibs,INTBIG dependentlibcount,TECHNOLOGY * tech)569 BOOLEAN us_tecedmakelayers(LIBRARY **dependentlibs, INTBIG dependentlibcount, TECHNOLOGY *tech)
570 {
571 	REGISTER NODEPROTO *np;
572 	NODEPROTO **sequence, **nodesequence;
573 	REGISTER INTBIG i, j, l, total, nodecount, *drcptr, drcsize;
574 	REGISTER CHAR *ab;
575 	REGISTER VARIABLE *var;
576 	REGISTER void *infstr;
577 
578 	/* first find the number of layers */
579 	tech->layercount = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("layer-"),
580 		x_("EDTEC_layersequence"), &sequence);
581 	if (tech->layercount <= 0)
582 	{
583 		ttyputerr(_("No layers found"));
584 		if ((us_tool->toolstate&NODETAILS) == 0)
585 			ttyputerr(_("Create them with the 'edit-layer' option"));
586 		return(TRUE);
587 	}
588 
589 	/* allocate the arrays for the layers */
590 	us_teclayer_count = tech->layercount;
591 	drcsize = us_teclayer_count*us_teclayer_count/2 + (us_teclayer_count+1)/2;
592 
593 	us_teclayer_iname = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
594 	if (us_teclayer_iname == 0) return(TRUE);
595 	for(i=0; i<us_teclayer_count; i++) us_teclayer_iname[i] = 0;
596 
597 	tech->layers = (GRAPHICS **)emalloc(((us_teclayer_count+1) * (sizeof (GRAPHICS *))), tech->cluster);
598 	if (tech->layers == 0) return(TRUE);
599 	for(i=0; i<us_teclayer_count; i++) tech->layers[i] = (GRAPHICS *)emalloc(sizeof (GRAPHICS), tech->cluster);
600 	tech->layers[us_teclayer_count] = NOGRAPHICS;
601 
602 	us_teclayer_names = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
603 	if (us_teclayer_names == 0) return(TRUE);
604 	for(i=0; i<us_teclayer_count; i++) us_teclayer_names[i] = 0;
605 
606 	us_teccif_layers = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
607 	if (us_teccif_layers == 0) return(TRUE);
608 	for(i=0; i<us_teclayer_count; i++) us_teccif_layers[i] = 0;
609 
610 	us_tecdxf_layers = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
611 	if (us_tecdxf_layers == 0) return(TRUE);
612 	for(i=0; i<us_teclayer_count; i++) us_tecdxf_layers[i] = 0;
613 
614 	us_tecgds_layers = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
615 	if (us_tecgds_layers == 0) return(TRUE);
616 	for(i=0; i<us_teclayer_count; i++) us_tecgds_layers[i] = 0;
617 
618 	us_teclayer_function = emalloc((us_teclayer_count * SIZEOFINTBIG), us_tool->cluster);
619 	if (us_teclayer_function == 0) return(TRUE);
620 
621 	us_teclayer_letters = (CHAR **)emalloc((us_teclayer_count * (sizeof (CHAR *))), us_tool->cluster);
622 	if (us_teclayer_letters == 0) return(TRUE);
623 	for(i=0; i<us_teclayer_count; i++) us_teclayer_letters[i] = 0;
624 
625 	us_tecspice_res = (float *)emalloc((us_teclayer_count * (sizeof (float))), us_tool->cluster);
626 	if (us_tecspice_res == 0) return(TRUE);
627 	for(i=0; i<us_teclayer_count; i++) us_tecspice_res[i] = 0.0;
628 
629 	us_tecspice_cap = (float *)emalloc((us_teclayer_count * (sizeof (float))), us_tool->cluster);
630 	if (us_tecspice_cap == 0) return(TRUE);
631 	for(i=0; i<us_teclayer_count; i++) us_tecspice_cap[i] = 0.0;
632 
633 	us_tecspice_ecap = (float *)emalloc((us_teclayer_count * (sizeof (float))), us_tool->cluster);
634 	if (us_tecspice_ecap == 0) return(TRUE);
635 	for(i=0; i<us_teclayer_count; i++) us_tecspice_ecap[i] = 0.0;
636 
637 	us_tec3d_height = (INTBIG *)emalloc((us_teclayer_count * SIZEOFINTBIG), us_tool->cluster);
638 	if (us_tec3d_height == 0) return(TRUE);
639 	for(i=0; i<us_teclayer_count; i++) us_tec3d_height[i] = 0;
640 
641 	us_tec3d_thickness = (INTBIG *)emalloc((us_teclayer_count * SIZEOFINTBIG), us_tool->cluster);
642 	if (us_tec3d_thickness == 0) return(TRUE);
643 	for(i=0; i<us_teclayer_count; i++) us_tec3d_thickness[i] = 0;
644 
645 	us_tecprint_colors = (INTBIG *)emalloc((us_teclayer_count * 5 * SIZEOFINTBIG), us_tool->cluster);
646 	if (us_tecprint_colors == 0) return(TRUE);
647 	for(i=0; i<us_teclayer_count*5; i++) us_tecprint_colors[i] = 0;
648 
649 	/* get the design rules */
650 	us_tecedgetlayernamelist();
651 	if (us_tecdrc_rules != 0)
652 	{
653 		dr_freerules(us_tecdrc_rules);
654 		us_tecdrc_rules = 0;
655 	}
656 	nodecount = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("node-"),
657 		x_("EDTEC_nodesequence"), &nodesequence);
658 	us_tecdrc_rules = dr_allocaterules(us_teceddrclayers, nodecount, x_("EDITED TECHNOLOGY"));
659 	if (us_tecdrc_rules == NODRCRULES) return(TRUE);
660 	for(i=0; i<us_teceddrclayers; i++)
661 		(void)allocstring(&us_tecdrc_rules->layernames[i], us_teceddrclayernames[i], el_tempcluster);
662 	for(i=0; i<nodecount; i++)
663 		(void)allocstring(&us_tecdrc_rules->nodenames[i], &nodesequence[i]->protoname[5], el_tempcluster);
664 	if (nodecount > 0) efree((CHAR *)nodesequence);
665 	var = NOVARIABLE;
666 	for(i=dependentlibcount-1; i>=0; i--)
667 	{
668 		var = getval((INTBIG)dependentlibs[i], VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_DRC"));
669 		if (var != NOVARIABLE) break;
670 	}
671 	us_teceditgetdrcarrays(var, us_tecdrc_rules);
672 
673 	/* now scan each layer and fill in the data */
674 	for(total=0; total<us_teclayer_count; total++)
675 	{
676 		/* set the layer name */
677 		np = sequence[total];
678 		(void)allocstring(&us_teclayer_names[total], &np->protoname[6], us_tool->cluster);
679 
680 		if (us_teceditgetlayerinfo(np, tech->layers[total], &us_teccif_layers[total],
681 			&us_teclayer_function[total], &us_teclayer_letters[total], &us_tecdxf_layers[total],
682 				&us_tecgds_layers[total], &us_tecspice_res[total], &us_tecspice_cap[total],
683 					&us_tecspice_ecap[total], &us_tecdrc_rules->minwidth[total],
684 						&us_tec3d_height[total], &us_tec3d_thickness[total],
685 							&us_tecprint_colors[total*5])) return(TRUE);
686 		if (us_teccif_layers[total] != 0 && namesame(us_teccif_layers[total], x_("xx")) != 0)
687 			us_tecflags |= HASCIF;
688 		if (us_tecdxf_layers[total] != 0) us_tecflags |= HASDXF;
689 		if (us_tecgds_layers[total] != 0) us_tecflags |= HASGDS;
690 		if (us_tecspice_res[total] != 0.0) us_tecflags |= HASSPIRES;
691 		if (us_tecspice_cap[total] != 0.0) us_tecflags |= HASSPICAP;
692 		if (us_tecspice_ecap[total] != 0.0) us_tecflags |= HASSPIECAP;
693 		if (us_tec3d_height[total] != 0 || us_tec3d_thickness[total] != 0) us_tecflags |= HAS3DINFO;
694 		if (us_tecprint_colors[total*5] != 0 || us_tecprint_colors[total*5+1] != 0 ||
695 			us_tecprint_colors[total*5+2] != 0 || us_tecprint_colors[total*5+3] != 0 ||
696 			us_tecprint_colors[total*5+4] != 0) us_tecflags |= HASPRINTCOL;
697 		tech->layers[total]->firstvar = NOVARIABLE;
698 		tech->layers[total]->numvar = 0;
699 	}
700 
701 	for(i=0; i<total; i++)
702 	{
703 		(void)allocstring(&us_teclayer_iname[i], makeabbrev(us_teclayer_names[i], TRUE),
704 			us_tool->cluster);
705 
706 		/* loop until the name is unique */
707 		for(;;)
708 		{
709 			/* see if a previously assigned abbreviation is the same */
710 			for(j=0; j<i; j++)
711 				if (namesame(us_teclayer_iname[i], us_teclayer_iname[j]) == 0)
712 					break;
713 			if (j >= i) break;
714 
715 			/* name conflicts: change it */
716 			l = estrlen(ab = us_teclayer_iname[i]);
717 			if (ab[l-1] >= '0' && ab[l-1] <= '8') ab[l-1]++; else
718 			{
719 				infstr = initinfstr();
720 				addstringtoinfstr(infstr, ab);
721 				addtoinfstr(infstr, '0');
722 				(void)reallocstring(&us_teclayer_iname[i], returninfstr(infstr), us_tool->cluster);
723 			}
724 		}
725 	}
726 
727 	/* get the color map */
728 	var = NOVARIABLE;
729 	for(i=dependentlibcount-1; i>=0; i--)
730 	{
731 		var = getval((INTBIG)dependentlibs[i], VLIBRARY, VINTEGER|VISARRAY, x_("EDTEC_colormap"));
732 		if (var != NOVARIABLE) break;
733 	}
734 	if (var != NOVARIABLE)
735 	{
736 		us_tecflags |= HASCOLORMAP;
737 		drcptr = (INTBIG *)var->addr;
738 		for(i=0; i<32; i++)
739 		{
740 			us_teccolmap[i].red = (INTSML)drcptr[(i<<2)*3];
741 			us_teccolmap[i].green = (INTSML)drcptr[(i<<2)*3+1];
742 			us_teccolmap[i].blue = (INTSML)drcptr[(i<<2)*3+2];
743 		}
744 	}
745 
746 	/* see which design rules exist */
747 	for(i=0; i<us_teceddrclayers; i++)
748 	{
749 		if (us_tecdrc_rules->minwidth[i] >= 0) us_tecflags |= HASDRCMINWID;
750 		if (*us_tecdrc_rules->minwidthR[i] != 0) us_tecflags |= HASDRCMINWIDR;
751 	}
752 	for(i=0; i<drcsize; i++)
753 	{
754 		if (us_tecdrc_rules->conlist[i] >= 0) us_tecflags |= HASCONDRC;
755 		if (*us_tecdrc_rules->conlistR[i] != 0) us_tecflags |= HASCONDRCR;
756 		if (us_tecdrc_rules->unconlist[i] >= 0) us_tecflags |= HASUNCONDRC;
757 		if (*us_tecdrc_rules->unconlistR[i] != 0) us_tecflags |= HASUNCONDRCR;
758 		if (us_tecdrc_rules->conlistW[i] >= 0) us_tecflags |= HASCONDRCW;
759 		if (*us_tecdrc_rules->conlistWR[i] != 0) us_tecflags |= HASCONDRCWR;
760 		if (us_tecdrc_rules->unconlistW[i] >= 0) us_tecflags |= HASUNCONDRCW;
761 		if (*us_tecdrc_rules->unconlistWR[i] != 0) us_tecflags |= HASUNCONDRCWR;
762 		if (us_tecdrc_rules->conlistM[i] >= 0) us_tecflags |= HASCONDRCM;
763 		if (*us_tecdrc_rules->conlistMR[i] != 0) us_tecflags |= HASCONDRCMR;
764 		if (us_tecdrc_rules->unconlistM[i] >= 0) us_tecflags |= HASUNCONDRCM;
765 		if (*us_tecdrc_rules->unconlistMR[i] != 0) us_tecflags |= HASUNCONDRCMR;
766 		if (us_tecdrc_rules->edgelist[i] >= 0) us_tecflags |= HASEDGEDRC;
767 		if (*us_tecdrc_rules->edgelistR[i] != 0) us_tecflags |= HASEDGEDRCR;
768 	}
769 	for(i=0; i<us_tecdrc_rules->numnodes; i++)
770 	{
771 		if (us_tecdrc_rules->minnodesize[i*2] > 0 ||
772 			us_tecdrc_rules->minnodesize[i*2+1] > 0) us_tecflags |= HASMINNODE;
773 		if (*us_tecdrc_rules->minnodesizeR[i] != 0) us_tecflags |= HASMINNODER;
774 	}
775 
776 	/* store this information on the technology object */
777 	(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_layer_names"), (INTBIG)us_teclayer_names,
778 		VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
779 	(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_layer_function"), (INTBIG)us_teclayer_function,
780 		VINTEGER|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
781 	(void)setvalkey((INTBIG)tech, VTECHNOLOGY, us_layer_letters_key, (INTBIG)us_teclayer_letters,
782 		VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
783 	if ((us_tecflags&HASCOLORMAP) != 0)
784 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("USER_color_map"), (INTBIG)us_teccolmap,
785 			VCHAR|VDONTSAVE|VISARRAY|((sizeof us_teccolmap)<<VLENGTHSH));
786 	if ((us_tecflags&HASCIF) != 0)
787 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("IO_cif_layer_names"), (INTBIG)us_teccif_layers,
788 			VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
789 	if ((us_tecflags&HASDXF) != 0)
790 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("IO_dxf_layer_names"), (INTBIG)us_tecdxf_layers,
791 			VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
792 	if ((us_tecflags&HASGDS) != 0)
793 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("IO_gds_layer_numbers"), (INTBIG)us_tecgds_layers,
794 			VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
795 
796 	if ((us_tecflags&(HASCONDRCW|HASUNCONDRCW)) != 0)
797 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_wide_limitkey, us_tecdrc_rules->widelimit,
798 			VFRACT|VDONTSAVE);
799 	if ((us_tecflags&HASDRCMINWID) != 0)
800 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_min_widthkey, (INTBIG)us_tecdrc_rules->minwidth,
801 			VFRACT|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
802 	if ((us_tecflags&HASDRCMINWIDR) != 0)
803 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_min_width_rulekey, (INTBIG)us_tecdrc_rules->minwidthR,
804 			VSTRING|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
805 	if ((us_tecflags&HASCONDRC) != 0)
806 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distanceskey,
807 			(INTBIG)us_tecdrc_rules->conlist, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
808 	if ((us_tecflags&HASCONDRCR) != 0)
809 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distances_rulekey,
810 			(INTBIG)us_tecdrc_rules->conlistR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
811 	if ((us_tecflags&HASUNCONDRC) != 0)
812 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distanceskey,
813 			(INTBIG)us_tecdrc_rules->unconlist, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
814 	if ((us_tecflags&HASUNCONDRCR) != 0)
815 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distances_rulekey,
816 			(INTBIG)us_tecdrc_rules->unconlistR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
817 	if ((us_tecflags&HASCONDRCW) != 0)
818 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distancesWkey,
819 			(INTBIG)us_tecdrc_rules->conlistW, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
820 	if ((us_tecflags&HASCONDRCWR) != 0)
821 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distancesW_rulekey,
822 			(INTBIG)us_tecdrc_rules->conlistWR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
823 	if ((us_tecflags&HASUNCONDRCW) != 0)
824 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distancesWkey,
825 			(INTBIG)us_tecdrc_rules->unconlistW, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
826 	if ((us_tecflags&HASUNCONDRCWR) != 0)
827 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distancesW_rulekey,
828 			(INTBIG)us_tecdrc_rules->unconlistWR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
829 	if ((us_tecflags&HASCONDRCM) != 0)
830 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distancesMkey,
831 			(INTBIG)us_tecdrc_rules->conlistM, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
832 	if ((us_tecflags&HASCONDRCMR) != 0)
833 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_connected_distancesM_rulekey,
834 			(INTBIG)us_tecdrc_rules->conlistMR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
835 	if ((us_tecflags&HASUNCONDRCM) != 0)
836 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distancesMkey,
837 			(INTBIG)us_tecdrc_rules->unconlistM, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
838 	if ((us_tecflags&HASUNCONDRCMR) != 0)
839 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_unconnected_distancesM_rulekey,
840 			(INTBIG)us_tecdrc_rules->unconlistMR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
841 	if ((us_tecflags&HASEDGEDRC) != 0)
842 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_edge_distanceskey,
843 			(INTBIG)us_tecdrc_rules->edgelist, VFRACT|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
844 	if ((us_tecflags&HASEDGEDRCR) != 0)
845 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_edge_distances_rulekey,
846 			(INTBIG)us_tecdrc_rules->edgelistR, VSTRING|VDONTSAVE|VISARRAY|(drcsize<<VLENGTHSH));
847 	if ((us_tecflags&HASMINNODE) != 0)
848 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_min_node_sizekey,
849 			(INTBIG)us_tecdrc_rules->minnodesize, VFRACT|VDONTSAVE|VISARRAY|((us_tecdrc_rules->numnodes*2)<<VLENGTHSH));
850 	if ((us_tecflags&HASMINNODER) != 0)
851 		(void)setvalkey((INTBIG)tech, VTECHNOLOGY, dr_min_node_size_rulekey,
852 			(INTBIG)us_tecdrc_rules->minnodesizeR, VSTRING|VDONTSAVE|VISARRAY|(us_tecdrc_rules->numnodes<<VLENGTHSH));
853 	if ((us_tecflags&HASSPIRES) != 0)
854 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("SIM_spice_resistance"), (INTBIG)us_tecspice_res,
855 			VFLOAT|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
856 	if ((us_tecflags&HASSPICAP) != 0)
857 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("SIM_spice_capacitance"), (INTBIG)us_tecspice_cap,
858 			VFLOAT|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
859 	if ((us_tecflags&HASSPIECAP) != 0)
860 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("SIM_spice_edge_capacitance"), (INTBIG)us_tecspice_ecap,
861 			VFLOAT|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
862 	if ((us_tecflags&HAS3DINFO) != 0)
863 	{
864 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_layer_3dheight"), (INTBIG)us_tec3d_height,
865 			VINTEGER|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
866 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_layer_3dthickness"), (INTBIG)us_tec3d_thickness,
867 			VINTEGER|VDONTSAVE|VISARRAY|(tech->layercount<<VLENGTHSH));
868 	}
869 	if ((us_tecflags&HASPRINTCOL) != 0)
870 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("USER_print_colors"), (INTBIG)us_tecprint_colors,
871 			VINTEGER|VDONTSAVE|VISARRAY|((tech->layercount*5)<<VLENGTHSH));
872 
873 
874 	efree((CHAR *)sequence);
875 	return(FALSE);
876 }
877 
878 /*
879  * routine to scan the "dependentlibcount" libraries in "dependentlibs",
880  * and build the arc structures for it in technology "tech".  Returns true on error.
881  */
us_tecedmakearcs(LIBRARY ** dependentlibs,INTBIG dependentlibcount,TECHNOLOGY * tech)882 BOOLEAN us_tecedmakearcs(LIBRARY **dependentlibs, INTBIG dependentlibcount,
883 	TECHNOLOGY *tech)
884 {
885 	REGISTER NODEPROTO *np;
886 	NODEPROTO **sequence;
887 	REGISTER INTBIG arcindex, count, j, k, layerindex, typ;
888 	REGISTER INTBIG maxwid, hwid, wid, lambda;
889 	REGISTER CHAR *str;
890 	REGISTER NODEINST *ni;
891 	REGISTER EXAMPLE *nelist;
892 	REGISTER SAMPLE *ns;
893 	REGISTER VARIABLE *var;
894 
895 	/* count the number of arcs in the technology */
896 	us_tecarc_count = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("arc-"),
897 		x_("EDTEC_arcsequence"), &sequence);
898 	if (us_tecarc_count <= 0)
899 	{
900 		ttyputerr(_("No arcs found"));
901 		if ((us_tool->toolstate&NODETAILS) == 0)
902 			ttyputerr(_("Create them with the 'edit-arc' option"));
903 		return(TRUE);
904 	}
905 	tech->arcprotocount = us_tecarc_count;
906 
907 	/* allocate the arcs */
908 	tech->arcprotos = (TECH_ARCS **)emalloc(((us_tecarc_count+1) * (sizeof (TECH_ARCS *))),
909 		tech->cluster);
910 	if (tech->arcprotos == 0) return(TRUE);
911 	tech->arcprotos[us_tecarc_count] = ((TECH_ARCS *)-1);
912 	us_tecarc_widoff = emalloc((us_tecarc_count * SIZEOFINTBIG), us_tool->cluster);
913 	if (us_tecarc_widoff == 0) return(TRUE);
914 
915 	/* create the arc structures */
916 	lambda = el_curlib->lambda[art_tech->techindex];
917 	for(arcindex=0; arcindex<us_tecarc_count; arcindex++)
918 	{
919 		/* build a list of examples found in this arc */
920 		np = sequence[arcindex];
921 		nelist = us_tecedgetexamples(np, FALSE);
922 		if (nelist == NOEXAMPLE) return(TRUE);
923 		if (nelist->nextexample != NOEXAMPLE)
924 		{
925 			us_tecedpointout(NONODEINST, np);
926 			ttyputerr(_("Can only be one example of %s but more were found"),
927 				describenodeproto(np));
928 			us_tecedfreeexamples(nelist);
929 			return(TRUE);
930 		}
931 
932 		/* get width and polygon count information */
933 		count = 0;
934 		maxwid = hwid = -1;
935 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
936 		{
937 			wid = mini(ns->node->highx - ns->node->lowx, ns->node->highy - ns->node->lowy);
938 			if (wid > maxwid) maxwid = wid;
939 			if (ns->layer == NONODEPROTO) hwid = wid; else count++;
940 		}
941 
942 		/* error if there is no highlight box */
943 		if (hwid < 0)
944 		{
945 			us_tecedpointout(NONODEINST, np);
946 			ttyputerr(_("No highlight layer found in %s"), describenodeproto(np));
947 			if ((us_tool->toolstate&NODETAILS) == 0)
948 				ttyputmsg(_("Use 'place-layer' option to create HIGHLIGHT"));
949 			us_tecedfreeexamples(nelist);
950 			return(TRUE);
951 		}
952 
953 		/* create and fill the basic structure entries for this arc */
954 		tech->arcprotos[arcindex] = (TECH_ARCS *)emalloc(sizeof (TECH_ARCS), tech->cluster);
955 		if (tech->arcprotos[arcindex] == 0) return(TRUE);
956 		(void)allocstring(&tech->arcprotos[arcindex]->arcname, &np->protoname[4],
957 			tech->cluster);
958 		tech->arcprotos[arcindex]->arcwidth = maxwid * WHOLE / lambda;
959 		tech->arcprotos[arcindex]->arcindex = arcindex;
960 		tech->arcprotos[arcindex]->creation = NOARCPROTO;
961 		tech->arcprotos[arcindex]->laycount = count;
962 		us_tecarc_widoff[arcindex] = (maxwid - hwid) * WHOLE / lambda;
963 		if (us_tecarc_widoff[arcindex] != 0) us_tecflags |= HASARCWID;
964 
965 		/* look for descriptive nodes in the cell */
966 		tech->arcprotos[arcindex]->initialbits = 0;
967 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
968 		{
969 			typ = us_tecedgetoption(ni);
970 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
971 			if (var == NOVARIABLE) continue;
972 
973 			/* the "Function:" node */
974 			if (typ == ARCFUNCTION)
975 			{
976 				str = us_teceditgetparameter(var);
977 				for(j=0; us_tecarc_functions[j].name != 0; j++)
978 					if (namesame(str, us_tecarc_functions[j].name) == 0)
979 				{
980 					tech->arcprotos[arcindex]->initialbits |=
981 						(us_tecarc_functions[j].value << AFUNCTIONSH);
982 					break;
983 				}
984 			}
985 
986 			/* the "Fixed-angle:" node */
987 			if (typ == ARCFIXANG)
988 			{
989 				str = (CHAR *)var->addr;
990 				if (str[9] == ':') str = &str[11]; else str = &str[13];
991 				if (namesame(str, x_("yes")) == 0)
992 					tech->arcprotos[arcindex]->initialbits |= WANTFIXANG;
993 			}
994 
995 			/* the "Wipes pins:" node */
996 			if (typ == ARCWIPESPINS)
997 			{
998 				str = us_teceditgetparameter(var);
999 				if (namesame(str, x_("yes")) == 0)
1000 					tech->arcprotos[arcindex]->initialbits |= CANWIPE;
1001 			}
1002 
1003 			/* the "Extend arcs:" node */
1004 			if (typ == ARCNOEXTEND)
1005 			{
1006 				str = us_teceditgetparameter(var);
1007 				if (namesame(str, x_("no")) == 0)
1008 					tech->arcprotos[arcindex]->initialbits |= WANTNOEXTEND;
1009 			}
1010 
1011 			/* the "Angle increment:" node */
1012 			if (typ == ARCINC)
1013 			{
1014 				str = us_teceditgetparameter(var);
1015 				j = myatoi(str) % 360;
1016 				if (j < 0) j += 360;
1017 				tech->arcprotos[arcindex]->initialbits &= ~AANGLEINC;
1018 				tech->arcprotos[arcindex]->initialbits |= (j << AANGLEINCSH);
1019 			}
1020 		}
1021 
1022 		/* allocate the individual arc layer structures */
1023 		tech->arcprotos[arcindex]->list = (TECH_ARCLAY *)emalloc((count * (sizeof (TECH_ARCLAY))),
1024 			tech->cluster);
1025 		if (tech->arcprotos[arcindex]->list == 0) return(TRUE);
1026 
1027 		/* fill the individual arc layer structures */
1028 		layerindex = 0;
1029 		for(k=0; k<2; k++)
1030 			for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1031 		{
1032 			if (ns->layer == NONODEPROTO) continue;
1033 
1034 			/* get the layer index */
1035 			for(j=0; j<tech->layercount; j++)
1036 				if (namesame(&ns->layer->protoname[6], us_teclayer_names[j]) == 0) break;
1037 			if (j >= tech->layercount)
1038 			{
1039 				ttyputerr(_("Cannot find layer %s, used in %s"), describenodeproto(ns->layer),
1040 					describenodeproto(np));
1041 				us_tecedfreeexamples(nelist);
1042 				return(TRUE);
1043 			}
1044 
1045 			/* only add transparent layers when k=0 */
1046 			if (k == 0)
1047 			{
1048 				if (tech->layers[j]->bits == LAYERO) continue;
1049 			} else
1050 			{
1051 				if (tech->layers[j]->bits != LAYERO) continue;
1052 			}
1053 
1054 			tech->arcprotos[arcindex]->list[layerindex].lay = j;
1055 
1056 			/* determine the style of this arc layer */
1057 			if (ns->node->proto == art_filledboxprim)
1058 				tech->arcprotos[arcindex]->list[layerindex].style = FILLED; else
1059 					tech->arcprotos[arcindex]->list[layerindex].style = CLOSED;
1060 
1061 			/* determine the width offset of this arc layer */
1062 			wid = mini(ns->node->highx-ns->node->lowx, ns->node->highy-ns->node->lowy);
1063 			tech->arcprotos[arcindex]->list[layerindex].off = (maxwid-wid) * WHOLE /
1064 				lambda;
1065 
1066 			layerindex++;
1067 		}
1068 		us_tecedfreeexamples(nelist);
1069 	}
1070 
1071 	/* store width offset on the technology */
1072 	if ((us_tecflags&HASARCWID) != 0)
1073 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_arc_width_offset"), (INTBIG)us_tecarc_widoff,
1074 			VFRACT|VDONTSAVE|VISARRAY|(us_tecarc_count<<VLENGTHSH));
1075 	efree((CHAR *)sequence);
1076 	return(FALSE);
1077 }
1078 
1079 /*
1080  * routine to scan the "dependentlibcount" libraries in "dependentlibs",
1081  * and build the node structures for it in technology "tech".  Returns true on error.
1082  */
us_tecedmakenodes(LIBRARY ** dependentlibs,INTBIG dependentlibcount,TECHNOLOGY * tech)1083 BOOLEAN us_tecedmakenodes(LIBRARY **dependentlibs, INTBIG dependentlibcount,
1084 	TECHNOLOGY *tech)
1085 {
1086 	REGISTER NODEPROTO *np;
1087 	NODEPROTO **sequence;
1088 	REGISTER NODEINST *ni;
1089 	REGISTER VARIABLE *var;
1090 	REGISTER CHAR *str, *portname;
1091 	REGISTER INTBIG *list, save1, nfunction, x1pos, x2pos, y1pos, y2pos, net, lambda;
1092 	REGISTER INTBIG i, j, k, l, m, pass, nodeindex, sty, difindex, polindex,
1093 		serpdifind, opt, nsindex, err, portchecked;
1094 	INTBIG pol1port, pol2port, dif1port, dif2port;
1095 	INTBIG serprule[8];
1096 	REGISTER EXAMPLE *nelist;
1097 	REGISTER SAMPLE *ns, *ons, *diflayer, *pollayer;
1098 	REGISTER PCON *pc;
1099 	REGISTER RULE *r;
1100 	REGISTER TECH_NODES *tlist;
1101 
1102 	/* no rectangle rules */
1103 	us_tecedfirstrule = NORULE;
1104 
1105 	us_tecnode_count = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("node-"),
1106 		x_("EDTEC_nodesequence"), &sequence);
1107 	if (us_tecnode_count <= 0)
1108 	{
1109 		ttyputerr(_("No nodes found"));
1110 		if ((us_tool->toolstate&NODETAILS) == 0)
1111 			ttyputerr(_("Create them with the 'edit-node' option"));
1112 		return(TRUE);
1113 	}
1114 	tech->nodeprotocount = us_tecnode_count;
1115 
1116 	/* allocate the nodes */
1117 	tech->nodeprotos = (TECH_NODES **)emalloc((us_tecnode_count+1) *
1118 		(sizeof (TECH_NODES *)), tech->cluster);
1119 	if (tech->nodeprotos == 0) return(TRUE);
1120 	tech->nodeprotos[us_tecnode_count] = ((TECH_NODES *)-1);
1121 	us_tecnode_widoff = emalloc((4*us_tecnode_count * SIZEOFINTBIG), us_tool->cluster);
1122 	if (us_tecnode_widoff == 0) return(TRUE);
1123 	us_tecnode_grab = emalloc((3*us_tecnode_count * SIZEOFINTBIG), us_tool->cluster);
1124 	if (us_tecnode_grab == 0) return(TRUE);
1125 	us_tecnode_grabcount = 0;
1126 
1127 	/* get the nodes */
1128 	lambda = el_curlib->lambda[art_tech->techindex];
1129 	nodeindex = 0;
1130 	for(pass=0; pass<3; pass++)
1131 		for(m=0; m<us_tecnode_count; m++)
1132 	{
1133 		/* make sure this is the right type of node for this pass of the nodes */
1134 		np = sequence[m];
1135 		nfunction = NPUNKNOWN;
1136 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1137 		{
1138 			/* get the node function */
1139 			if (us_tecedgetoption(ni) != NODEFUNCTION) continue;
1140 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1141 			if (var == NOVARIABLE) continue;
1142 			str = us_teceditgetparameter(var);
1143 			for(j=0; j<MAXNODEFUNCTION; j++)
1144 				if (namesame(str, nodefunctionname(j, NONODEINST)) == 0) break;
1145 			if (j < MAXNODEFUNCTION)
1146 			{
1147 				nfunction = j;
1148 				break;
1149 			}
1150 		}
1151 
1152 		/* only want pins on pass 0, pure-layer nodes on pass 2 */
1153 		if (pass == 0 && nfunction != NPPIN) continue;
1154 		if (pass == 1 && (nfunction == NPPIN || nfunction == NPNODE)) continue;
1155 		if (pass == 2 && nfunction != NPNODE) continue;
1156 
1157 		/* build a list of examples found in this node */
1158 		nelist = us_tecedgetexamples(np, TRUE);
1159 		if (nelist == NOEXAMPLE) return(TRUE);
1160 
1161 		/* associate the samples in each example */
1162 		if (us_tecedassociateexamples(nelist, np))
1163 		{
1164 			us_tecedfreeexamples(nelist);
1165 			return(TRUE);
1166 		}
1167 
1168 		/* allocate and fill the TECH_NODES structure */
1169 		tlist = (TECH_NODES *)emalloc(sizeof (TECH_NODES), tech->cluster);
1170 		if (tlist == 0) return(TRUE);
1171 		tech->nodeprotos[nodeindex] = tlist;
1172 		(void)allocstring(&tlist->nodename, &np->protoname[5], tech->cluster);
1173 		tlist->nodeindex = (INTSML)(nodeindex + 1);
1174 		tlist->creation = NONODEPROTO;
1175 		tlist->xsize = (nelist->hx-nelist->lx)*WHOLE/lambda;
1176 		tlist->ysize = (nelist->hy-nelist->ly)*WHOLE/lambda;
1177 		tlist->layerlist = 0;
1178 		tlist->layercount = 0;
1179 		tlist->special = 0;
1180 		tlist->f1 = 0;
1181 		tlist->f2 = 0;
1182 		tlist->f3 = 0;
1183 		tlist->f4 = 0;
1184 		tlist->f5 = 0;
1185 		tlist->f6 = 0;
1186 		tlist->gra = 0;
1187 		tlist->ele = 0;
1188 
1189 		/* determine user bits */
1190 		tlist->initialbits = nfunction<<NFUNCTIONSH;
1191 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1192 		{
1193 			opt = us_tecedgetoption(ni);
1194 
1195 			/* pick up square node information */
1196 			if (opt == NODESQUARE)
1197 			{
1198 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1199 				if (var == NOVARIABLE) continue;
1200 				str = us_teceditgetparameter(var);
1201 				if (namesame(str, x_("yes")) == 0) tlist->initialbits |= NSQUARE;
1202 				continue;
1203 			}
1204 
1205 			/* pick up invisible on 1 or 2 arc information */
1206 			if (opt == NODEWIPES)
1207 			{
1208 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1209 				if (var == NOVARIABLE) continue;
1210 				str = us_teceditgetparameter(var);
1211 				if (namesame(str, x_("yes")) == 0)
1212 					tlist->initialbits = WIPEON1OR2 | (tlist->initialbits & ~(ARCSWIPE|ARCSHRINK));
1213 				continue;
1214 			}
1215 
1216 			/* pick up lockable information */
1217 			if (opt == NODELOCKABLE)
1218 			{
1219 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1220 				if (var == NOVARIABLE) continue;
1221 				str = us_teceditgetparameter(var);
1222 				if (namesame(str, x_("yes")) == 0) tlist->initialbits |= LOCKEDPRIM;
1223 				continue;
1224 			}
1225 
1226 			/* pick up multicut information */
1227 			if (opt == NODEMULTICUT)
1228 			{
1229 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1230 				if (var == NOVARIABLE) continue;
1231 				str = us_teceditgetparameter(var);
1232 				tlist->f4 = (INTSML)atofr(str);
1233 				continue;
1234 			}
1235 
1236 			/* pick up serpentine transistor information */
1237 			if (opt == NODESERPENTINE)
1238 			{
1239 				var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
1240 				if (var == NOVARIABLE) continue;
1241 				str = us_teceditgetparameter(var);
1242 				if (namesame(str, x_("yes")) == 0)
1243 				{
1244 					if (tlist->special != 0)
1245 					{
1246 						us_tecedpointout(ni, np);
1247 						ttyputerr(_("Serpentine %s must have Transistor function"),
1248 							describenodeproto(np));
1249 						us_tecedfreeexamples(nelist);
1250 						return(TRUE);
1251 					}
1252 					tlist->special = SERPTRANS;
1253 					tlist->initialbits |= (NODESHRINK | HOLDSTRACE);
1254 				}
1255 				continue;
1256 			}
1257 		}
1258 
1259 		/* derive primitives from the examples */
1260 		if (us_tecedmakeprim(nelist, np, tech, tlist, lambda))
1261 		{
1262 			us_tecedfreeexamples(nelist);
1263 			efree((CHAR *)tlist->nodename);
1264 			efree((CHAR *)tlist);
1265 			return(TRUE);
1266 		}
1267 
1268 		/* analyze special node function circumstances */
1269 		switch (nfunction)
1270 		{
1271 			case NPNODE:
1272 				if (tlist->special != 0)
1273 				{
1274 					us_tecedpointout(NONODEINST, np);
1275 					ttyputerr(_("Pure layer %s can not be serpentine"), describenodeproto(np));
1276 					us_tecedfreeexamples(nelist);
1277 					return(TRUE);
1278 				}
1279 				tlist->special = POLYGONAL;
1280 				tlist->initialbits |= HOLDSTRACE;
1281 				break;
1282 			case NPPIN:
1283 				if ((tlist->initialbits&WIPEON1OR2) == 0)
1284 				{
1285 					tlist->initialbits |= ARCSWIPE;
1286 					tlist->initialbits |= ARCSHRINK;
1287 				}
1288 				break;
1289 		}
1290 
1291 		/* count the number of ports on this node */
1292 		tlist->portcount = 0;
1293 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1294 			if (ns->layer == gen_portprim) tlist->portcount++;
1295 		if (tlist->portcount == 0)
1296 		{
1297 			us_tecedpointout(NONODEINST, np);
1298 			ttyputerr(_("No ports found in %s"), describenodeproto(np));
1299 			if ((us_tool->toolstate&NODETAILS) == 0)
1300 				ttyputmsg(_("Use 'place-layer port' option to create one"));
1301 			us_tecedfreeexamples(nelist);
1302 			return(TRUE);
1303 		}
1304 
1305 		/* allocate space for the ports */
1306 		tlist->portlist = (TECH_PORTS *)emalloc((tlist->portcount * (sizeof (TECH_PORTS))),
1307 			tech->cluster);
1308 		if (tlist->portlist == 0) return(TRUE);
1309 
1310 		/* fill the port structures */
1311 		pol1port = pol2port = dif1port = dif2port = -1;
1312 		i = 0;
1313 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1314 		{
1315 			if (ns->layer != gen_portprim) continue;
1316 
1317 			/* port connections */
1318 			var = getval((INTBIG)ns->node, VNODEINST, VNODEPROTO|VISARRAY, x_("EDTEC_connects"));
1319 			if (var == NOVARIABLE) pc = us_tecedaddportlist(0, (INTBIG *)0); else
1320 			{
1321 				/* convert "arc-CELL" pointers to indices */
1322 				l = getlength(var);
1323 				list = emalloc((l * SIZEOFINTBIG), el_tempcluster);
1324 				if (list == 0) return(TRUE);
1325 				portchecked = 0;
1326 				for(j=0; j<l; j++)
1327 				{
1328 					/* find arc that connects */
1329 					for(k=0; k<tech->arcprotocount; k++)
1330 						if (namesame(tech->arcprotos[k]->arcname,
1331 							&((NODEPROTO **)var->addr)[j]->protoname[4]) == 0) break;
1332 					if (k >= tech->arcprotocount)
1333 					{
1334 						us_tecedpointout(ns->node, ns->node->parent);
1335 						ttyputerr(_("Invalid connection list on port in %s"),
1336 							describenodeproto(np));
1337 						if ((us_tool->toolstate&NODETAILS) == 0)
1338 							ttyputmsg(_("Use 'change' option to remove arc %s"),
1339 								&((NODEPROTO **)var->addr)[j]->protoname[4]);
1340 						us_tecedfreeexamples(nelist);
1341 						return(TRUE);
1342 					}
1343 
1344 					/* fill in the connection information */
1345 					list[j] = k;
1346 
1347 					/* find port characteristics for possible transistors */
1348 					if (portchecked != 0) continue;
1349 					switch ((tech->arcprotos[k]->initialbits&AFUNCTION)>>AFUNCTIONSH)
1350 					{
1351 						case APPOLY1:   case APPOLY2:
1352 							if (pol1port < 0)
1353 							{
1354 								pol1port = i;
1355 								portchecked++;
1356 							} else if (pol2port < 0)
1357 							{
1358 								pol2port = i;
1359 								portchecked++;
1360 							}
1361 							break;
1362 						case APDIFF:    case APDIFFP:   case APDIFFN:
1363 						case APDIFFS:   case APDIFFW:
1364 							if (dif1port < 0)
1365 							{
1366 								dif1port = i;
1367 								portchecked++;
1368 							} else if (dif2port < 0)
1369 							{
1370 								dif2port = i;
1371 								portchecked++;
1372 							}
1373 							break;
1374 					}
1375 				}
1376 
1377 				/* store complete list in memory */
1378 				pc = us_tecedaddportlist(l, list);
1379 				efree((CHAR *)list);
1380 			}
1381 
1382 			/* link connection list to the port */
1383 			if (pc == NOPCON) return(TRUE);
1384 			tlist->portlist[i].portarcs = pc->connects;
1385 
1386 			/* port name */
1387 			portname = us_tecedgetportname(ns->node);
1388 			if (portname == 0)
1389 			{
1390 				us_tecedpointout(ns->node, np);
1391 				ttyputerr(_("Cell %s: port does not have a name"), describenodeproto(np));
1392 				us_tecedfreeexamples(nelist);
1393 				return(TRUE);
1394 			}
1395 			for(str = portname; *str != 0; str++)
1396 				if (*str <= ' ' || *str >= 0177)
1397 			{
1398 				us_tecedpointout(ns->node, np);
1399 				ttyputerr(_("Invalid port name '%s' in %s"), portname,
1400 					describenodeproto(np));
1401 				us_tecedfreeexamples(nelist);
1402 				return(TRUE);
1403 			}
1404 			(void)allocstring(&tlist->portlist[i].protoname, portname, tech->cluster);
1405 
1406 			/* port angle and range */
1407 			tlist->portlist[i].initialbits = 0;
1408 			var = getval((INTBIG)ns->node, VNODEINST, VINTEGER, x_("EDTEC_portangle"));
1409 			if (var != NOVARIABLE)
1410 				tlist->portlist[i].initialbits |= var->addr << PORTANGLESH;
1411 			var = getval((INTBIG)ns->node, VNODEINST, VINTEGER, x_("EDTEC_portrange"));
1412 			if (var != NOVARIABLE)
1413 				tlist->portlist[i].initialbits |= var->addr << PORTARANGESH; else
1414 					tlist->portlist[i].initialbits |= 180 << PORTARANGESH;
1415 
1416 			/* port connectivity */
1417 			net = i;
1418 			if (ns->node->firstportarcinst != NOPORTARCINST)
1419 			{
1420 				j = 0;
1421 				for(ons = nelist->firstsample; ons != ns; ons = ons->nextsample)
1422 				{
1423 					if (ons->layer != gen_portprim) continue;
1424 					if (ons->node->firstportarcinst != NOPORTARCINST)
1425 					{
1426 						if (ns->node->firstportarcinst->conarcinst->network ==
1427 							ons->node->firstportarcinst->conarcinst->network)
1428 						{
1429 							net = j;
1430 							break;
1431 						}
1432 					}
1433 					j++;
1434 				}
1435 			}
1436 			tlist->portlist[i].initialbits |= (net << PORTNETSH);
1437 
1438 			/* port area rule */
1439 			r = ns->rule;
1440 			if (r == NORULE) continue;
1441 			tlist->portlist[i].lowxmul = (INTSML)r->value[0];
1442 			tlist->portlist[i].lowxsum = (INTSML)r->value[1];
1443 			tlist->portlist[i].lowymul = (INTSML)r->value[2];
1444 			tlist->portlist[i].lowysum = (INTSML)r->value[3];
1445 			tlist->portlist[i].highxmul = (INTSML)r->value[4];
1446 			tlist->portlist[i].highxsum = (INTSML)r->value[5];
1447 			tlist->portlist[i].highymul = (INTSML)r->value[6];
1448 			tlist->portlist[i].highysum = (INTSML)r->value[7];
1449 			i++;
1450 		}
1451 
1452 		/* on FET transistors, make sure ports 0 and 2 are poly */
1453 		if (nfunction == NPTRANMOS || nfunction == NPTRADMOS || nfunction == NPTRAPMOS ||
1454 			nfunction == NPTRADMES || nfunction == NPTRAEMES)
1455 		{
1456 			if (pol1port < 0 || pol2port < 0 || dif1port < 0 || dif2port < 0)
1457 			{
1458 				us_tecedpointout(NONODEINST, np);
1459 				ttyputerr(_("Need 2 gate and 2 active ports on field-effect transistor %s"),
1460 					describenodeproto(np));
1461 				us_tecedfreeexamples(nelist);
1462 				return(TRUE);
1463 			}
1464 			if (pol1port != 0)
1465 			{
1466 				if (pol2port == 0) us_tecedswapports(&pol1port, &pol2port, tlist); else
1467 				if (dif1port == 0) us_tecedswapports(&pol1port, &dif1port, tlist); else
1468 				if (dif2port == 0) us_tecedswapports(&pol1port, &dif2port, tlist);
1469 			}
1470 			if (pol2port != 2)
1471 			{
1472 				if (dif1port == 2) us_tecedswapports(&pol2port, &dif1port, tlist); else
1473 				if (dif2port == 2) us_tecedswapports(&pol2port, &dif2port, tlist);
1474 			}
1475 			if (dif1port != 1) us_tecedswapports(&dif1port, &dif2port, tlist);
1476 
1477 			/* also make sure that dif1port is positive and dif2port is negative */
1478 			x1pos = (tlist->portlist[dif1port].lowxmul*tlist->xsize +
1479 				tlist->portlist[dif1port].lowxsum +
1480 					tlist->portlist[dif1port].highxmul*tlist->xsize +
1481 						tlist->portlist[dif1port].highxsum) / 2;
1482 			x2pos = (tlist->portlist[dif2port].lowxmul*tlist->xsize +
1483 				tlist->portlist[dif2port].lowxsum +
1484 					tlist->portlist[dif2port].highxmul*tlist->xsize +
1485 						tlist->portlist[dif2port].highxsum) / 2;
1486 			y1pos = (tlist->portlist[dif1port].lowymul*tlist->ysize +
1487 				tlist->portlist[dif1port].lowysum +
1488 					tlist->portlist[dif1port].highymul*tlist->ysize +
1489 						tlist->portlist[dif1port].highysum) / 2;
1490 			y2pos = (tlist->portlist[dif2port].lowymul*tlist->ysize +
1491 				tlist->portlist[dif2port].lowysum +
1492 					tlist->portlist[dif2port].highymul*tlist->ysize +
1493 						tlist->portlist[dif2port].highysum) / 2;
1494 			if (abs(x1pos-x2pos) > abs(y1pos-y2pos))
1495 			{
1496 				if (x1pos < x2pos)
1497 				{
1498 					us_tecedswapports(&dif1port, &dif2port, tlist);
1499 					j = dif1port;   dif1port = dif2port;   dif2port = j;
1500 				}
1501 			} else
1502 			{
1503 				if (y1pos < y2pos)
1504 				{
1505 					us_tecedswapports(&dif1port, &dif2port, tlist);
1506 					j = dif1port;   dif1port = dif2port;   dif2port = j;
1507 				}
1508 			}
1509 
1510 			/* also make sure that pol1port is negative and pol2port is positive */
1511 			x1pos = (tlist->portlist[pol1port].lowxmul*tlist->xsize +
1512 				tlist->portlist[pol1port].lowxsum +
1513 					tlist->portlist[pol1port].highxmul*tlist->xsize +
1514 						tlist->portlist[pol1port].highxsum) / 2;
1515 			x2pos = (tlist->portlist[pol2port].lowxmul*tlist->xsize +
1516 				tlist->portlist[pol2port].lowxsum +
1517 					tlist->portlist[pol2port].highxmul*tlist->xsize +
1518 						tlist->portlist[pol2port].highxsum) / 2;
1519 			y1pos = (tlist->portlist[pol1port].lowymul*tlist->ysize +
1520 				tlist->portlist[pol1port].lowysum +
1521 					tlist->portlist[pol1port].highymul*tlist->ysize +
1522 						tlist->portlist[pol1port].highysum) / 2;
1523 			y2pos = (tlist->portlist[pol2port].lowymul*tlist->ysize +
1524 				tlist->portlist[pol2port].lowysum +
1525 					tlist->portlist[pol2port].highymul*tlist->ysize +
1526 						tlist->portlist[pol2port].highysum) / 2;
1527 			if (abs(x1pos-x2pos) > abs(y1pos-y2pos))
1528 			{
1529 				if (x1pos > x2pos)
1530 				{
1531 					us_tecedswapports(&pol1port, &pol2port, tlist);
1532 					j = pol1port;   pol1port = pol2port;   pol2port = j;
1533 				}
1534 			} else
1535 			{
1536 				if (y1pos > y2pos)
1537 				{
1538 					us_tecedswapports(&pol1port, &pol2port, tlist);
1539 					j = pol1port;   pol1port = pol2port;   pol2port = j;
1540 				}
1541 			}
1542 		}
1543 
1544 		/* count the number of layers on the node */
1545 		tlist->layercount = 0;
1546 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1547 		{
1548 			if (ns->rule != NORULE && ns->layer != gen_portprim &&
1549 				ns->layer != gen_cellcenterprim && ns->layer != NONODEPROTO)
1550 					tlist->layercount++;
1551 		}
1552 
1553 		/* allocate space for the layers */
1554 		if (tlist->special != SERPTRANS)
1555 		{
1556 			tlist->layerlist = (TECH_POLYGON *)emalloc((tlist->layercount *
1557 				(sizeof (TECH_POLYGON))), tech->cluster);
1558 			if (tlist->layerlist == 0) return(TRUE);
1559 		} else
1560 		{
1561 			tlist->gra = (TECH_SERPENT *)emalloc(((sizeof (TECH_SERPENT)) * tlist->layercount),
1562 				tech->cluster);
1563 			if (tlist->gra == 0) return(TRUE);
1564 			tlist->ele = (TECH_SERPENT *)emalloc(((sizeof (TECH_SERPENT)) * (tlist->layercount+1)),
1565 				tech->cluster);
1566 			if (tlist->ele == 0) return(TRUE);
1567 		}
1568 
1569 		/* fill the layer structures (3 times: transparent, opaque, multicut) */
1570 		i = 0;
1571 		pollayer = diflayer = NOSAMPLE;
1572 		for(k=0; k<3; k++)
1573 			for(nsindex=0, ns = nelist->firstsample; ns != NOSAMPLE; nsindex++, ns = ns->nextsample)
1574 		{
1575 			r = ns->rule;
1576 			if (r == NORULE || ns->layer == gen_portprim ||
1577 				ns->layer == gen_cellcenterprim || ns->layer == NONODEPROTO) continue;
1578 
1579 			/* add cut layers last (only when k=2) */
1580 			if (k == 2)
1581 			{
1582 				if (!r->multicut) continue;
1583 				if (tlist->special != 0)
1584 				{
1585 					us_tecedpointout(ns->node, ns->node->parent);
1586 					ttyputerr(_("%s is too complex (multiple cuts AND serpentine)"),
1587 						describenodeproto(np));
1588 					us_tecedfreeexamples(nelist);
1589 					return(TRUE);
1590 				}
1591 				tlist->special = MULTICUT;
1592 				tlist->f1 = (INTSML)(r->multixs*WHOLE/lambda);
1593 				tlist->f2 = (INTSML)(r->multiys*WHOLE/lambda);
1594 				tlist->f3 = (INTSML)(r->multiindent*WHOLE/lambda);
1595 				tlist->f4 = (INTSML)(r->multisep*WHOLE/lambda);
1596 			} else
1597 			{
1598 				if (r->multicut) continue;
1599 			}
1600 
1601 			/* layer number */
1602 			for(j=0; j<tech->layercount; j++)
1603 				if (namesame(&ns->layer->protoname[6], us_teclayer_names[j]) == 0) break;
1604 			if (j >= tech->layercount)
1605 			{
1606 				ttyputerr(_("Cannot find layer %s in %s"), describenodeproto(ns->layer),
1607 					describenodeproto(np));
1608 				return(TRUE);
1609 			}
1610 
1611 			/* only add transparent layers when k=0 */
1612 			if (k == 0)
1613 			{
1614 				if (tech->layers[j]->bits == LAYERO) continue;
1615 			} else if (k == 1)
1616 			{
1617 				if (tech->layers[j]->bits != LAYERO) continue;
1618 			}
1619 
1620 			/* layer style */
1621 			sty = -1;
1622 			if (ns->node->proto == art_filledboxprim)             sty = FILLEDRECT; else
1623 			if (ns->node->proto == art_boxprim)                   sty = CLOSEDRECT; else
1624 			if (ns->node->proto == art_crossedboxprim)            sty = CROSSED; else
1625 			if (ns->node->proto == art_filledpolygonprim)         sty = FILLED; else
1626 			if (ns->node->proto == art_closedpolygonprim)         sty = CLOSED; else
1627 			if (ns->node->proto == art_openedpolygonprim)         sty = OPENED; else
1628 			if (ns->node->proto == art_openeddottedpolygonprim)   sty = OPENEDT1; else
1629 			if (ns->node->proto == art_openeddashedpolygonprim)   sty = OPENEDT2; else
1630 			if (ns->node->proto == art_openedthickerpolygonprim)  sty = OPENEDT3; else
1631 			if (ns->node->proto == art_filledcircleprim)          sty = DISC; else
1632 			if (ns->node->proto == art_circleprim)
1633 			{
1634 				var = getvalkey((INTBIG)ns->node, VNODEINST, VINTEGER, art_degreeskey);
1635 				if (var != NOVARIABLE) sty = CIRCLEARC; else sty = CIRCLE;
1636 			} else if (ns->node->proto == art_thickcircleprim)
1637 			{
1638 				var = getvalkey((INTBIG)ns->node, VNODEINST, VINTEGER, art_degreeskey);
1639 				if (var != NOVARIABLE) sty = THICKCIRCLEARC; else sty = THICKCIRCLE;
1640 			} else if (ns->node->proto == gen_invispinprim)
1641 			{
1642 				var = getvalkey((INTBIG)ns->node, VNODEINST, VSTRING|VISARRAY, art_messagekey);
1643 				if (var != NOVARIABLE)
1644 				{
1645 					switch (TDGETPOS(var->textdescript))
1646 					{
1647 						case VTPOSBOXED:     sty = TEXTBOX;       break;
1648 						case VTPOSCENT:      sty = TEXTCENT;      break;
1649 						case VTPOSUP:        sty = TEXTBOT;       break;
1650 						case VTPOSDOWN:      sty = TEXTTOP;       break;
1651 						case VTPOSLEFT:      sty = TEXTRIGHT;     break;
1652 						case VTPOSRIGHT:     sty = TEXTLEFT;      break;
1653 						case VTPOSUPLEFT:    sty = TEXTBOTRIGHT;  break;
1654 						case VTPOSUPRIGHT:   sty = TEXTBOTLEFT;   break;
1655 						case VTPOSDOWNLEFT:  sty = TEXTTOPRIGHT;  break;
1656 						case VTPOSDOWNRIGHT: sty = TEXTTOPLEFT;   break;
1657 					}
1658 				}
1659 			}
1660 			if (sty == -1)
1661 				ttyputmsg(_("Cannot determine style to use for %s node in %s"),
1662 					describenodeproto(ns->node->proto), describenodeproto(np));
1663 
1664 			/* load the layer structure(s) */
1665 			if (tlist->special == SERPTRANS)
1666 			{
1667 				/* determine port numbers for serpentine transistors */
1668 				if (layerismetal(us_teclayer_function[j]))
1669 				{
1670 					tlist->gra[i].basics.portnum = 0;
1671 				} else if (layerispoly(us_teclayer_function[j]))
1672 				{
1673 					pollayer = ns;
1674 					if (pol1port >= 0)
1675 						tlist->gra[i].basics.portnum = (INTSML)pol1port; else
1676 							tlist->gra[i].basics.portnum = 0;
1677 					polindex = i;
1678 				} else if ((us_teclayer_function[j]&LFTYPE) == LFDIFF)
1679 				{
1680 					diflayer = ns;
1681 					difindex = i;
1682 					tlist->gra[i].basics.portnum = 0;
1683 				} else
1684 				{
1685 					tlist->gra[i].basics.portnum = -1;
1686 				}
1687 
1688 				tlist->gra[i].basics.layernum = (INTSML)j;
1689 				tlist->gra[i].basics.count = (INTSML)(r->count/4);
1690 				if (sty == CROSSED || sty == FILLEDRECT || sty == FILLED || sty == CLOSEDRECT ||
1691 					sty == CLOSED)
1692 				{
1693 					if (tlist->gra[i].basics.count == 4)
1694 					{
1695 						ttyputmsg(_("Ignoring Minimum-Size setting on layer %s in serpentine transistor %s"),
1696 							&ns->layer->protoname[6], &np->protoname[5]);
1697 						tlist->gra[i].basics.count = 2;
1698 					}
1699 				}
1700 				tlist->gra[i].basics.style = (INTSML)sty;
1701 				if (tlist->gra[i].basics.count == 2 && (sty == CROSSED ||
1702 					sty == FILLEDRECT || sty == FILLED || sty == CLOSEDRECT || sty == CLOSED))
1703 				{
1704 					tlist->gra[i].basics.representation = BOX;
1705 					tlist->gra[i].basics.count = 4;
1706 				} else tlist->gra[i].basics.representation = POINTS;
1707 				tlist->gra[i].basics.points = r->value;
1708 				tlist->gra[i].lwidth = (INTSML)nsindex;
1709 				tlist->gra[i].rwidth = 0;
1710 				tlist->gra[i].extendt = 0;
1711 				tlist->gra[i].extendb = 0;
1712 			} else
1713 			{
1714 				tlist->layerlist[i].portnum = (INTSML)us_tecedfindport(tlist, nelist,
1715 					ns->node->lowx, ns->node->highx, ns->node->lowy, ns->node->highy,
1716 						lambdaofnode(ns->node));
1717 				tlist->layerlist[i].layernum = (INTSML)j;
1718 				tlist->layerlist[i].count = (INTSML)(r->count/4);
1719 				tlist->layerlist[i].style = (INTSML)sty;
1720 				tlist->layerlist[i].representation = POINTS;
1721 				if (sty == CROSSED || sty == FILLEDRECT || sty == FILLED || sty == CLOSEDRECT ||
1722 					sty == CLOSED)
1723 				{
1724 					if (r->count == 8)
1725 					{
1726 						tlist->layerlist[i].representation = BOX;
1727 						tlist->layerlist[i].count = 4;
1728 					} else if (r->count == 16)
1729 					{
1730 						tlist->layerlist[i].representation = MINBOX;
1731 						tlist->layerlist[i].count = 4;
1732 					}
1733 				}
1734 				tlist->layerlist[i].points = r->value;
1735 			}
1736 
1737 			/* mark this rectangle rule "used" */
1738 			r->used = TRUE;
1739 			i++;
1740 		}
1741 
1742 		/* finish up serpentine transistors */
1743 		if (tlist->special == SERPTRANS)
1744 		{
1745 			if (diflayer == NOSAMPLE || pollayer == NOSAMPLE || dif1port < 0)
1746 			{
1747 				us_tecedpointout(NONODEINST, np);
1748 				ttyputerr(_("No diffusion and polysilicon layers in transistor %s"),
1749 					describenodeproto(np));
1750 				us_tecedfreeexamples(nelist);
1751 				return(TRUE);
1752 			}
1753 
1754 			/* compute port extension factors */
1755 			tlist->f1 = tlist->layercount+1;
1756 			if (tlist->portlist[dif1port].lowxsum >
1757 				tlist->portlist[dif1port].lowysum)
1758 			{
1759 				/* vertical diffusion layer: determine polysilicon width */
1760 				tlist->f4 = (INTSML)((muldiv(tlist->ysize, tlist->gra[polindex].basics.points[6], WHOLE) +
1761 					tlist->gra[polindex].basics.points[7]) -
1762 						(muldiv(tlist->ysize, tlist->gra[polindex].basics.points[2], WHOLE) +
1763 							tlist->gra[polindex].basics.points[3]));
1764 
1765 				/* determine diffusion port rule */
1766 				tlist->f2 = (INTSML)((muldiv(tlist->xsize, tlist->portlist[dif1port].lowxmul, WHOLE) +
1767 					tlist->portlist[dif1port].lowxsum) -
1768 						(muldiv(tlist->xsize, tlist->gra[difindex].basics.points[0], WHOLE) +
1769 							tlist->gra[difindex].basics.points[1]));
1770 				tlist->f3 = (INTSML)((muldiv(tlist->ysize, tlist->portlist[dif1port].lowymul, WHOLE) +
1771 					tlist->portlist[dif1port].lowysum) -
1772 						(muldiv(tlist->ysize, tlist->gra[polindex].basics.points[6], WHOLE) +
1773 							tlist->gra[polindex].basics.points[7]));
1774 
1775 				/* determine polysilicon port rule */
1776 				tlist->f5 = (INTSML)((muldiv(tlist->ysize, tlist->portlist[pol1port].lowymul, WHOLE) +
1777 					tlist->portlist[pol1port].lowysum) -
1778 						(muldiv(tlist->ysize, tlist->gra[polindex].basics.points[2], WHOLE) +
1779 							tlist->gra[polindex].basics.points[3]));
1780 				tlist->f6 = (INTSML)((muldiv(tlist->xsize, tlist->gra[difindex].basics.points[0], WHOLE) +
1781 					tlist->gra[difindex].basics.points[1]) -
1782 						(muldiv(tlist->xsize, tlist->portlist[pol1port].highxmul, WHOLE) +
1783 							tlist->portlist[pol1port].highxsum));
1784 			} else
1785 			{
1786 				/* horizontal diffusion layer: determine polysilicon width */
1787 				tlist->f4 = (INTSML)((muldiv(tlist->xsize, tlist->gra[polindex].basics.points[4], WHOLE) +
1788 					tlist->gra[polindex].basics.points[5]) -
1789 						(muldiv(tlist->xsize, tlist->gra[polindex].basics.points[0], WHOLE) +
1790 							tlist->gra[polindex].basics.points[1]));
1791 
1792 				/* determine diffusion port rule */
1793 				tlist->f2 = (INTSML)((muldiv(tlist->ysize, tlist->portlist[dif1port].lowymul, WHOLE) +
1794 					tlist->portlist[dif1port].lowysum) -
1795 						(muldiv(tlist->ysize, tlist->gra[difindex].basics.points[2], WHOLE) +
1796 							tlist->gra[difindex].basics.points[3]));
1797 				tlist->f3 = (INTSML)((muldiv(tlist->xsize, tlist->gra[polindex].basics.points[0], WHOLE) +
1798 					tlist->gra[polindex].basics.points[1]) -
1799 						(muldiv(tlist->xsize, tlist->portlist[dif1port].highxmul, WHOLE) +
1800 							tlist->portlist[dif1port].highxsum));
1801 
1802 				/* determine polysilicon port rule */
1803 				tlist->f5 = (INTSML)((muldiv(tlist->xsize, tlist->portlist[pol1port].lowxmul, WHOLE) +
1804 					tlist->portlist[pol1port].lowxsum) -
1805 						(muldiv(tlist->xsize, tlist->gra[polindex].basics.points[0], WHOLE) +
1806 							tlist->gra[polindex].basics.points[1]));
1807 				tlist->f6 = (INTSML)((muldiv(tlist->ysize, tlist->gra[difindex].basics.points[2], WHOLE) +
1808 					tlist->gra[difindex].basics.points[3]) -
1809 						(muldiv(tlist->ysize, tlist->portlist[pol1port].highymul, WHOLE) +
1810 							tlist->portlist[pol1port].highysum));
1811 			}
1812 
1813 			/* find width and extension from comparison to poly layer */
1814 			for(i=0; i<tlist->layercount; i++)
1815 			{
1816 				for(nsindex=0, ns = nelist->firstsample; ns != NOSAMPLE;
1817 					nsindex++, ns = ns->nextsample)
1818 						if (tlist->gra[i].lwidth == nsindex) break;
1819 				if (ns == NOSAMPLE)
1820 				{
1821 					us_tecedpointout(NONODEINST, np);
1822 					ttyputerr(_("Internal error in serpentine %s"), describenodeproto(np));
1823 					us_tecedfreeexamples(nelist);
1824 					continue;
1825 				}
1826 
1827 				if (pollayer->node->highx-pollayer->node->lowx >
1828 					pollayer->node->highy-pollayer->node->lowy)
1829 				{
1830 					/* horizontal layer */
1831 					tlist->gra[i].lwidth = (INTSML)((ns->node->highy - (ns->parent->ly + ns->parent->hy)/2) *
1832 						WHOLE/lambda);
1833 					tlist->gra[i].rwidth = (INTSML)(((ns->parent->ly + ns->parent->hy)/2 - ns->node->lowy) *
1834 						WHOLE/lambda);
1835 					tlist->gra[i].extendt = (INTSML)((diflayer->node->lowx - ns->node->lowx) * WHOLE /
1836 						lambda);
1837 				} else
1838 				{
1839 					/* vertical layer */
1840 					tlist->gra[i].lwidth = (INTSML)((ns->node->highx - (ns->parent->lx + ns->parent->hx)/2) *
1841 						WHOLE/lambda);
1842 					tlist->gra[i].rwidth = (INTSML)(((ns->parent->lx + ns->parent->hx)/2 - ns->node->lowx) *
1843 						WHOLE/lambda);
1844 					tlist->gra[i].extendt = (INTSML)((diflayer->node->lowy - ns->node->lowy) * WHOLE /
1845 						lambda);
1846 				}
1847 				tlist->gra[i].extendb = tlist->gra[i].extendt;
1848 			}
1849 
1850 			/* copy basic graphics to electrical version, doubling diffusion */
1851 			i = 0;
1852 			for(j=0; j<tlist->layercount; j++)
1853 			{
1854 				if (j != difindex) k = 1; else
1855 				{
1856 					k = 2;
1857 
1858 					/* copy rectangle rule and prepare for electrical layers */
1859 					r = diflayer->rule;
1860 					if (r->count != 8)
1861 					{
1862 						us_tecedpointout(NONODEINST, np);
1863 						ttyputerr(_("Nonrectangular diffusion in Serpentine %s"),
1864 							describenodeproto(np));
1865 						us_tecedfreeexamples(nelist);
1866 						return(TRUE);
1867 					}
1868 					for(l=0; l<r->count; l++) serprule[l] = r->value[l];
1869 					if (serprule[0] != -H0 || serprule[2] != -H0 ||
1870 						serprule[4] != H0 || serprule[6] != H0)
1871 					{
1872 						us_tecedpointout(NONODEINST, np);
1873 						ttyputerr(_("Unusual diffusion in Serpentine %s"), describenodeproto(np));
1874 						us_tecedfreeexamples(nelist);
1875 						return(TRUE);
1876 					}
1877 					if (tlist->xsize - serprule[1] + serprule[5] <
1878 						tlist->ysize - serprule[3] + serprule[7]) serpdifind = 2; else
1879 							serpdifind = 0;
1880 				}
1881 				for(l=0; l<k; l++)
1882 				{
1883 					tlist->ele[i].basics.layernum = tlist->gra[j].basics.layernum;
1884 					tlist->ele[i].basics.count = tlist->gra[j].basics.count;
1885 					tlist->ele[i].basics.style = tlist->gra[j].basics.style;
1886 					tlist->ele[i].basics.representation = tlist->gra[j].basics.representation;
1887 					tlist->ele[i].basics.points = tlist->gra[j].basics.points;
1888 					tlist->ele[i].lwidth = tlist->gra[j].lwidth;
1889 					tlist->ele[i].rwidth = tlist->gra[j].rwidth;
1890 					tlist->ele[i].extendt = tlist->gra[j].extendt;
1891 					tlist->ele[i].extendb = tlist->gra[j].extendb;
1892 					if (k == 1) tlist->ele[i].basics.portnum = tlist->gra[j].basics.portnum; else
1893 						switch (l)
1894 					{
1895 						case 0:
1896 							tlist->ele[i].basics.portnum = (INTSML)dif1port;
1897 							tlist->ele[i].rwidth = -tlist->gra[polindex].lwidth;
1898 							save1 = serprule[serpdifind+1];
1899 
1900 							/* in transistor, diffusion stops in center */
1901 							serprule[serpdifind] = 0;
1902 							serprule[serpdifind+1] = 0;
1903 							r = us_tecedaddrule(serprule, 8, FALSE, (CHAR *)0);
1904 							if (r == NORULE) return(TRUE);
1905 							r->used = TRUE;
1906 							tlist->ele[i].basics.points = r->value;
1907 							serprule[serpdifind] = -H0;
1908 							serprule[serpdifind+1] = save1;
1909 							break;
1910 						case 1:
1911 							tlist->ele[i].basics.portnum = (INTSML)dif2port;
1912 							tlist->ele[i].lwidth = -tlist->gra[polindex].rwidth;
1913 							save1 = serprule[serpdifind+5];
1914 
1915 							/* in transistor, diffusion stops in center */
1916 							serprule[serpdifind+4] = 0;
1917 							serprule[serpdifind+5] = 0;
1918 							r = us_tecedaddrule(serprule, 8, FALSE, (CHAR *)0);
1919 							if (r == NORULE) return(TRUE);
1920 							r->used = TRUE;
1921 							tlist->ele[i].basics.points = r->value;
1922 							serprule[serpdifind+4] = H0;
1923 							serprule[serpdifind+5] = save1;
1924 							break;
1925 					}
1926 					i++;
1927 				}
1928 			}
1929 		}
1930 
1931 		/* extract width offset information */
1932 		us_tecnode_widoff[nodeindex*4] = 0;
1933 		us_tecnode_widoff[nodeindex*4+1] = 0;
1934 		us_tecnode_widoff[nodeindex*4+2] = 0;
1935 		us_tecnode_widoff[nodeindex*4+3] = 0;
1936 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1937 			if (ns->layer == NONODEPROTO) break;
1938 		if (ns != NOSAMPLE)
1939 		{
1940 			r = ns->rule;
1941 			if (r != NORULE)
1942 			{
1943 				err = 0;
1944 				switch (r->value[0])		/* left edge offset */
1945 				{
1946 					case -H0:
1947 						us_tecnode_widoff[nodeindex*4] = r->value[1];
1948 						break;
1949 					case H0:
1950 						us_tecnode_widoff[nodeindex*4] = tlist->xsize + r->value[1];
1951 						break;
1952 					default:
1953 						err++;
1954 						break;
1955 				}
1956 				switch (r->value[2])		/* bottom edge offset */
1957 				{
1958 					case -H0:
1959 						us_tecnode_widoff[nodeindex*4+2] = r->value[3];
1960 						break;
1961 					case H0:
1962 						us_tecnode_widoff[nodeindex*4+2] = tlist->ysize + r->value[3];
1963 						break;
1964 					default:
1965 						err++;
1966 						break;
1967 				}
1968 				switch (r->value[4])		/* right edge offset */
1969 				{
1970 					case H0:
1971 						us_tecnode_widoff[nodeindex*4+1] = -r->value[5];
1972 						break;
1973 					case -H0:
1974 						us_tecnode_widoff[nodeindex*4+1] = tlist->xsize - r->value[5];
1975 						break;
1976 					default:
1977 						err++;
1978 						break;
1979 				}
1980 				switch (r->value[6])		/* top edge offset */
1981 				{
1982 					case H0:
1983 						us_tecnode_widoff[nodeindex*4+3] = -r->value[7];
1984 						break;
1985 					case -H0:
1986 						us_tecnode_widoff[nodeindex*4+3] = tlist->ysize - r->value[7];
1987 						break;
1988 					default:
1989 						err++;
1990 						break;
1991 				}
1992 				if (err != 0)
1993 				{
1994 					us_tecedpointout(ns->node, ns->node->parent);
1995 					ttyputmsg(_("Highlighting cannot scale from center in %s"), describenodeproto(np));
1996 					us_tecedfreeexamples(nelist);
1997 					return(TRUE);
1998 				}
1999 			} else
2000 			{
2001 				us_tecedpointout(ns->node, ns->node->parent);
2002 				ttyputerr(_("No rule found for highlight in %s"), describenodeproto(np));
2003 				us_tecedfreeexamples(nelist);
2004 				return(TRUE);
2005 			}
2006 		} else
2007 		{
2008 			us_tecedpointout(NONODEINST, np);
2009 			ttyputerr(_("No highlight found in %s"), describenodeproto(np));
2010 			if ((us_tool->toolstate&NODETAILS) == 0)
2011 				ttyputmsg(_("Use 'place-layer' option to create HIGHLIGHT"));
2012 			us_tecedfreeexamples(nelist);
2013 			return(TRUE);
2014 		}
2015 
2016 		/* get grab point information */
2017 		for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
2018 			if (ns->layer == gen_cellcenterprim) break;
2019 		if (ns != NOSAMPLE)
2020 		{
2021 			us_tecnode_grab[us_tecnode_grabcount++] = nodeindex+1;
2022 			us_tecnode_grab[us_tecnode_grabcount++] = (ns->node->geom->lowx +
2023 				ns->node->geom->highx - nelist->lx - nelist->hx)/2 *
2024 				el_curlib->lambda[tech->techindex] / lambda;
2025 			us_tecnode_grab[us_tecnode_grabcount++] = (ns->node->geom->lowy +
2026 				ns->node->geom->highy - nelist->ly - nelist->hy)/2 *
2027 				el_curlib->lambda[tech->techindex] / lambda;
2028 			us_tecflags |= HASGRAB;
2029 		}
2030 
2031 		/* free all examples */
2032 		us_tecedfreeexamples(nelist);
2033 
2034 		/* advance the fill pointer */
2035 		nodeindex++;
2036 	}
2037 
2038 	/* store width offset on the technology */
2039 	(void)setval((INTBIG)tech, VTECHNOLOGY, x_("TECH_node_width_offset"), (INTBIG)us_tecnode_widoff,
2040 		VFRACT|VDONTSAVE|VISARRAY|((us_tecnode_count*4)<<VLENGTHSH));
2041 	efree((CHAR *)sequence);
2042 	return(FALSE);
2043 }
2044 
2045 /*
2046  * routine to find the closest port to the layer describe by "lx<=X<=hx" and
2047  * "ly<+Y<=hy" in the list "nelist".  The ports are listed in "tlist".  The algorithm
2048  * is to find a port that overlaps this layer.  If there is only one, or if all of
2049  * them electrically connect, use that.  If there are no such ports, or multiple
2050  * unconnected ports, presume that the layer is not related to any port.
2051  */
us_tecedfindport(TECH_NODES * tlist,EXAMPLE * nelist,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG lambda)2052 INTBIG us_tecedfindport(TECH_NODES *tlist, EXAMPLE *nelist, INTBIG lx, INTBIG hx, INTBIG ly,
2053 	INTBIG hy, INTBIG lambda)
2054 {
2055 	REGISTER INTBIG bestport, l, oldnet, newnet;
2056 	INTBIG portlx, porthx, portly, porthy;
2057 	REGISTER INTBIG swap;
2058 
2059 	bestport = -1;
2060 	for(l=0; l<tlist->portcount; l++)
2061 	{
2062 		subrange(nelist->lx, nelist->hx, tlist->portlist[l].lowxmul,
2063 			tlist->portlist[l].lowxsum, tlist->portlist[l].highxmul,
2064 				tlist->portlist[l].highxsum, &portlx, &porthx, lambda);
2065 		if (portlx > porthx)
2066 		{
2067 			swap = portlx;   portlx = porthx;   porthx = swap;
2068 		}
2069 		subrange(nelist->ly, nelist->hy, tlist->portlist[l].lowymul,
2070 			tlist->portlist[l].lowysum, tlist->portlist[l].highymul,
2071 				tlist->portlist[l].highysum, &portly, &porthy, lambda);
2072 		if (portlx > porthx)
2073 		{
2074 			swap = portly;   portly = porthy;   porthy = swap;
2075 		}
2076 
2077 		/* ignore the port if there is no intersection */
2078 		if (lx > porthx || hx < portlx || ly > porthy || hy < portly) continue;
2079 
2080 		/* if there is no previous overlapping port, use this */
2081 		if (bestport == -1)
2082 		{
2083 			bestport = l;
2084 			continue;
2085 		}
2086 
2087 		/* if these two ports connect, all is well */
2088 		newnet = (tlist->portlist[l].initialbits & PORTNET) >> PORTNETSH;
2089 		oldnet = (tlist->portlist[bestport].initialbits & PORTNET) >> PORTNETSH;
2090 		if (newnet == oldnet) continue;
2091 
2092 		/* two unconnected ports intersect layer: make it free */
2093 		return(-1);
2094 	}
2095 	return(bestport);
2096 }
2097 
2098 /*
2099  * Routine to free the examples created by "us_tecedgetexamples()".
2100  */
us_tecedfreeexamples(EXAMPLE * nelist)2101 void us_tecedfreeexamples(EXAMPLE *nelist)
2102 {
2103 	REGISTER EXAMPLE *ne;
2104 	REGISTER SAMPLE *ns;
2105 
2106 	while (nelist != NOEXAMPLE)
2107 	{
2108 		ne = nelist;
2109 		nelist = nelist->nextexample;
2110 		while (ne->firstsample != NOSAMPLE)
2111 		{
2112 			ns = ne->firstsample;
2113 			ne->firstsample = ne->firstsample->nextsample;
2114 			efree((CHAR *)ns);
2115 		}
2116 		efree((CHAR *)ne);
2117 	}
2118 }
2119 
2120 /*
2121  * routine to parse the node examples in cell "np" and return a list of
2122  * EXAMPLEs (one per example).  "isnode" is true if this is a node
2123  * being examined.  Returns NOEXAMPLE on error.
2124  */
us_tecedgetexamples(NODEPROTO * np,BOOLEAN isnode)2125 EXAMPLE *us_tecedgetexamples(NODEPROTO *np, BOOLEAN isnode)
2126 {
2127 	REGISTER SAMPLE *ns;
2128 	REGISTER EXAMPLE *ne, *nelist, *bestne;
2129 	REGISTER NODEINST *ni, *otherni;
2130 	REGISTER INTBIG sea, sizex, sizey, newsize, locx, locy, lambda, hcount, funct;
2131 	REGISTER BOOLEAN foundone, gotbbox;
2132 	INTBIG lx, hx, ly, hy, sflx, sfhx, sfly, sfhy;
2133 	REGISTER GEOM *geom;
2134 	XARRAY trans;
2135 	static POLYGON *poly = NOPOLYGON;
2136 
2137 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2138 	{
2139 		ni->temp1 = (INTBIG)NOEXAMPLE;
2140 
2141 		/* ignore special nodes with function information */
2142 		funct = us_tecedgetoption(ni);
2143 		if (funct != LAYERPATCH && funct != PORTOBJ && funct != HIGHLIGHTOBJ) ni->temp1 = 0;
2144 	}
2145 
2146 	nelist = NOEXAMPLE;
2147 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2148 	{
2149 		if (ni->temp1 != (INTBIG)NOEXAMPLE) continue;
2150 
2151 		/* get a new cluster of nodes */
2152 		ne = (EXAMPLE *)emalloc((sizeof (EXAMPLE)), us_tool->cluster);
2153 		if (ne == 0) return(NOEXAMPLE);
2154 		ne->firstsample = NOSAMPLE;
2155 		gotbbox = FALSE;
2156 		(void)needstaticpolygon(&poly, 4, us_tool->cluster);
2157 		nodesizeoffset(ni, &lx, &ly, &hx, &hy);
2158 		maketruerectpoly(ni->lowx+lx, ni->highx-hx, ni->lowy+ly, ni->highy-hy, poly);
2159 		makerot(ni, trans);
2160 		xformpoly(poly, trans);
2161 		getbbox(poly, &sflx, &sfhx, &sfly, &sfhy);
2162 		ne->nextexample = nelist;
2163 		nelist = ne;
2164 
2165 		/* now find all others that touch this area */
2166 		foundone = TRUE;
2167 		hcount = 0;
2168 		while (foundone)
2169 		{
2170 			foundone = FALSE;
2171 
2172 			/* begin to search the area so far */
2173 			sea = initsearch(sflx, sfhx, sfly, sfhy, np);
2174 			if (sea == -1) return(NOEXAMPLE);
2175 			for(;;)
2176 			{
2177 				/* get next node in the area */
2178 				geom = nextobject(sea);
2179 				if (geom == NOGEOM) break;
2180 				if (!geom->entryisnode) continue;
2181 				otherni = geom->entryaddr.ni;
2182 				(void)needstaticpolygon(&poly, 4, us_tool->cluster);
2183 				nodesizeoffset(otherni, &lx, &ly, &hx, &hy);
2184 				maketruerectpoly(otherni->lowx+lx, otherni->highx-hx, otherni->lowy+ly, otherni->highy-hy, poly);
2185 				makerot(otherni, trans);
2186 				xformpoly(poly, trans);
2187 				getbbox(poly, &lx, &hx, &ly, &hy);
2188 				if (hx < sflx || lx > sfhx || hy < sfly || ly > sfhy) continue;
2189 
2190 				/* make sure the node is valid */
2191 				if (otherni->temp1 != (INTBIG)NOEXAMPLE)
2192 				{
2193 					if (otherni->temp1 == 0) continue;
2194 					if (otherni->temp1 == (INTBIG)ne) continue;
2195 					us_tecedpointout(otherni, np);
2196 					ttyputerr(_("Examples are too close in %s"), describenodeproto(np));
2197 					termsearch(sea);
2198 					return(NOEXAMPLE);
2199 				}
2200 				otherni->temp1 = (INTBIG)ne;
2201 
2202 				/* add it to the cluster */
2203 				ns = (SAMPLE *)emalloc((sizeof (SAMPLE)), us_tool->cluster);
2204 				if (ns == 0) return(NOEXAMPLE);
2205 				ns->node = otherni;
2206 				ns->rule = NORULE;
2207 				ns->parent = ne;
2208 				ns->nextsample = ne->firstsample;
2209 				ne->firstsample = ns;
2210 				ns->assoc = NOSAMPLE;
2211 				ns->xpos = (lx + hx) / 2;
2212 				ns->ypos = (ly + hy) / 2;
2213 				if (otherni->proto == gen_portprim)
2214 				{
2215 					if (!isnode)
2216 					{
2217 						us_tecedpointout(otherni, np);
2218 						ttyputerr(_("%s cannot have ports.  Delete this"), describenodeproto(np));
2219 						termsearch(sea);
2220 						return(NOEXAMPLE);
2221 					}
2222 					ns->layer = gen_portprim;
2223 				} else if (otherni->proto == gen_cellcenterprim)
2224 				{
2225 					if (!isnode)
2226 					{
2227 						us_tecedpointout(otherni, np);
2228 						ttyputerr(_("%s cannot have a grab point.  Delete this"), describenodeproto(np));
2229 						termsearch(sea);
2230 						return(NOEXAMPLE);
2231 					}
2232 					ns->layer = gen_cellcenterprim;
2233 				} else
2234 				{
2235 					ns->layer = us_tecedgetlayer(otherni);
2236 					if (ns->layer == 0)
2237 					{
2238 						us_tecedpointout(otherni, np);
2239 						ttyputerr(_("No layer information on this sample in %s"),
2240 							describenodeproto(np));
2241 						if ((us_tool->toolstate&NODETAILS) == 0)
2242 							ttyputmsg(_("Use 'change' option or delete it"));
2243 						termsearch(sea);
2244 						return(NOEXAMPLE);
2245 					}
2246 					if (ns->layer == NONODEPROTO) hcount++;
2247 				}
2248 
2249 				/* accumulate state if this is not a "grab point" mark */
2250 				if (otherni->proto != gen_cellcenterprim)
2251 				{
2252 					if (!gotbbox)
2253 					{
2254 						ne->lx = lx;   ne->hx = hx;
2255 						ne->ly = ly;   ne->hy = hy;
2256 						gotbbox = TRUE;
2257 					} else
2258 					{
2259 						if (lx < ne->lx) ne->lx = lx;
2260 						if (hx > ne->hx) ne->hx = hx;
2261 						if (ly < ne->ly) ne->ly = ly;
2262 						if (hy > ne->hy) ne->hy = hy;
2263 					}
2264 					sflx = ne->lx;   sfhx = ne->hx;
2265 					sfly = ne->ly;   sfhy = ne->hy;
2266 				}
2267 				foundone = TRUE;
2268 			}
2269 		}
2270 		if (hcount == 0)
2271 		{
2272 			us_tecedpointout(NONODEINST, np);
2273 			ttyputerr(_("No highlight layer in %s example"), describenodeproto(np));
2274 			if ((us_tool->toolstate&NODETAILS) == 0)
2275 				ttyputmsg(_("Use 'place-layer' option to create HIGHLIGHT"));
2276 			return(NOEXAMPLE);
2277 		}
2278 		if (hcount != 1)
2279 		{
2280 			us_tecedpointout(NONODEINST, np);
2281 			ttyputerr(_("Too many highlight layers in %s example.  Delete some"), describenodeproto(np));
2282 			return(NOEXAMPLE);
2283 		}
2284 	}
2285 	if (nelist == NOEXAMPLE)
2286 	{
2287 		us_tecedpointout(NONODEINST, np);
2288 		ttyputerr(_("No examples found in %s"), describenodeproto(np));
2289 		if ((us_tool->toolstate&NODETAILS) == 0)
2290 			ttyputmsg(_("Use 'place-layer' option to produce some geometry"));
2291 		return(nelist);
2292 	}
2293 
2294 	/*
2295 	 * now search the list for the smallest, most upper-right example
2296 	 * (the "main" example)
2297 	 */
2298 	lambda = el_curlib->lambda[art_tech->techindex];
2299 	sizex = (nelist->hx - nelist->lx) / lambda;
2300 	sizey = (nelist->hy - nelist->ly) / lambda;
2301 	locx = (nelist->lx + nelist->hx) / 2;
2302 	locy = (nelist->ly + nelist->hy) / 2;
2303 	bestne = nelist;
2304 	for(ne = nelist; ne != NOEXAMPLE; ne = ne->nextexample)
2305 	{
2306 		newsize = (ne->hx-ne->lx) / lambda;
2307 		newsize *= (ne->hy-ne->ly) / lambda;
2308 		if (newsize > sizex*sizey) continue;
2309 		if (newsize == sizex*sizey && (ne->lx+ne->hx)/2 >= locx && (ne->ly+ne->hy)/2 <= locy)
2310 			continue;
2311 		sizex = (ne->hx - ne->lx) / lambda;
2312 		sizey = (ne->hy - ne->ly) / lambda;
2313 		locx = (ne->lx + ne->hx) / 2;
2314 		locy = (ne->ly + ne->hy) / 2;
2315 		bestne = ne;
2316 	}
2317 
2318 	/* place the main example at the top of the list */
2319 	if (bestne != nelist)
2320 	{
2321 		for(ne = nelist; ne != NOEXAMPLE; ne = ne->nextexample)
2322 			if (ne->nextexample == bestne)
2323 		{
2324 			ne->nextexample = bestne->nextexample;
2325 			break;
2326 		}
2327 		bestne->nextexample = nelist;
2328 		nelist = bestne;
2329 	}
2330 
2331 	/* done */
2332 	return(nelist);
2333 }
2334 
2335 /*
2336  * Routine to associate the samples of example "nelist" in cell "np"
2337  * Returns true if there is an error
2338  */
us_tecedassociateexamples(EXAMPLE * nelist,NODEPROTO * np)2339 BOOLEAN us_tecedassociateexamples(EXAMPLE *nelist, NODEPROTO *np)
2340 {
2341 	REGISTER EXAMPLE *ne;
2342 	REGISTER SAMPLE *ns, *nslist, *nsfound, **listsort, **thissort;
2343 	REGISTER INTBIG total, i;
2344 	REGISTER CHAR *name, *othername;
2345 
2346 	/* if there is only one example, no association */
2347 	if (nelist->nextexample == NOEXAMPLE) return(FALSE);
2348 
2349 	/* associate each example "ne" with the original in "nelist" */
2350 	for(ne = nelist->nextexample; ne != NOEXAMPLE; ne = ne->nextexample)
2351 	{
2352 		/* clear associations for every sample "ns" in the example "ne" */
2353 		for(ns = ne->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
2354 			ns->assoc = NOSAMPLE;
2355 
2356 		/* associate every sample "ns" in the example "ne" */
2357 		for(ns = ne->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
2358 		{
2359 			if (ns->assoc != NOSAMPLE) continue;
2360 
2361 			/* cannot have center in other examples */
2362 			if (ns->layer == gen_cellcenterprim)
2363 			{
2364 				us_tecedpointout(ns->node, ns->node->parent);
2365 				ttyputerr(_("Grab point should only be in main example of %s"),
2366 					describenodeproto(np));
2367 				return(TRUE);
2368 			}
2369 
2370 			/* count number of similar layers in original example "nelist" */
2371 			for(total = 0, nslist = nelist->firstsample; nslist != NOSAMPLE;
2372 				nslist = nslist->nextsample)
2373 			{
2374 				if (nslist->layer != ns->layer) continue;
2375 				total++;
2376 				nsfound = nslist;
2377 			}
2378 
2379 			/* no similar layer found in the original: error */
2380 			if (total == 0)
2381 			{
2382 				us_tecedpointout(ns->node, ns->node->parent);
2383 				ttyputerr(_("Layer %s not found in main example of %s"),
2384 					us_tecedsamplename(ns->layer), describenodeproto(np));
2385 				return(TRUE);
2386 			}
2387 
2388 			/* just one in the original: simple association */
2389 			if (total == 1)
2390 			{
2391 				ns->assoc = nsfound;
2392 				continue;
2393 			}
2394 
2395 			/* if it is a port, associate by port name */
2396 			if (ns->layer == gen_portprim)
2397 			{
2398 				name = us_tecedgetportname(ns->node);
2399 				if (name == 0)
2400 				{
2401 					us_tecedpointout(ns->node, ns->node->parent);
2402 					ttyputerr(_("Cell %s: port does not have a name"), describenodeproto(np));
2403 					return(TRUE);
2404 				}
2405 
2406 				/* search the original for that port */
2407 				for(nslist = nelist->firstsample; nslist != NOSAMPLE; nslist = nslist->nextsample)
2408 					if (nslist->layer == gen_portprim)
2409 				{
2410 					othername = us_tecedgetportname(nslist->node);
2411 					if (othername == 0)
2412 					{
2413 						us_tecedpointout(nslist->node, nslist->node->parent);
2414 						ttyputerr(_("Cell %s: port does not have a name"), describenodeproto(np));
2415 						return(TRUE);
2416 					}
2417 					if (namesame(name, othername) != 0) continue;
2418 					ns->assoc = nslist;
2419 					break;
2420 				}
2421 				if (nslist == NOSAMPLE)
2422 				{
2423 					us_tecedpointout(NONODEINST, np);
2424 					ttyputerr(_("Could not find port %s in all examples of %s"),
2425 						name, describenodeproto(np));
2426 					return(TRUE);
2427 				}
2428 				continue;
2429 			}
2430 
2431 			/* count the number of this layer in example "ne" */
2432 			for(i = 0, nslist = ne->firstsample; nslist != NOSAMPLE;
2433 				nslist = nslist->nextsample)
2434 					if (nslist->layer == ns->layer) i++;
2435 
2436 			/* if number of similar layers differs: error */
2437 			if (total != i)
2438 			{
2439 				us_tecedpointout(ns->node, ns->node->parent);
2440 				ttyputerr(_("Layer %s found %ld times in main example, %ld in other"),
2441 					us_tecedsamplename(ns->layer), total, i);
2442 				ttyputmsg(_("Make the counts consistent"));
2443 				return(TRUE);
2444 			}
2445 
2446 			/* make a list of samples on this layer in original */
2447 			listsort = (SAMPLE **)emalloc((total * (sizeof (SAMPLE *))), el_tempcluster);
2448 			if (listsort == 0) return(TRUE);
2449 			for(i = 0, nslist = nelist->firstsample; nslist != NOSAMPLE;
2450 				nslist = nslist->nextsample)
2451 					if (nslist->layer == ns->layer) listsort[i++] = nslist;
2452 
2453 			/* make a list of samples on this layer in example "ne" */
2454 			thissort = (SAMPLE **)emalloc((total * (sizeof (SAMPLE *))), el_tempcluster);
2455 			if (thissort == 0) return(TRUE);
2456 			for(i = 0, nslist = ne->firstsample; nslist != NOSAMPLE; nslist = nslist->nextsample)
2457 				if (nslist->layer == ns->layer) thissort[i++] = nslist;
2458 
2459 			/* sort each list in X/Y/shape */
2460 			esort(listsort, total, sizeof (SAMPLE *), us_samplecoordascending);
2461 			esort(thissort, total, sizeof (SAMPLE *), us_samplecoordascending);
2462 
2463 			/* see if the lists have duplication */
2464 			for(i=1; i<total; i++)
2465 				if ((thissort[i]->xpos == thissort[i-1]->xpos &&
2466 					thissort[i]->ypos == thissort[i-1]->ypos &&
2467 						thissort[i]->node->proto == thissort[i-1]->node->proto) ||
2468 					(listsort[i]->xpos == listsort[i-1]->xpos &&
2469 						listsort[i]->ypos == listsort[i-1]->ypos &&
2470 							listsort[i]->node->proto == listsort[i-1]->node->proto)) break;
2471 			if (i >= total)
2472 			{
2473 				/* association can be made in X */
2474 				for(i=0; i<total; i++) thissort[i]->assoc = listsort[i];
2475 				efree((CHAR *)thissort);
2476 				efree((CHAR *)listsort);
2477 				continue;
2478 			}
2479 
2480 			/* don't know how to associate this sample */
2481 			us_tecedpointout(thissort[i]->node, thissort[i]->node->parent);
2482 			ttyputerr(_("Sample %s is unassociated in %s"),
2483 				us_tecedsamplename(thissort[i]->layer), describenodeproto(np));
2484 			efree((CHAR *)thissort);
2485 			efree((CHAR *)listsort);
2486 			return(TRUE);
2487 		}
2488 
2489 		/* final check: make sure every sample in original example associates */
2490 		for(nslist = nelist->firstsample; nslist != NOSAMPLE;
2491 			nslist = nslist->nextsample) nslist->assoc = NOSAMPLE;
2492 		for(ns = ne->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
2493 			ns->assoc->assoc = ns;
2494 		for(nslist = nelist->firstsample; nslist != NOSAMPLE;
2495 			nslist = nslist->nextsample) if (nslist->assoc == NOSAMPLE)
2496 		{
2497 			if (nslist->layer == gen_cellcenterprim) continue;
2498 			us_tecedpointout(nslist->node, nslist->node->parent);
2499 			ttyputerr(_("Layer %s found in main example, but not others in %s"),
2500 				us_tecedsamplename(nslist->layer), describenodeproto(np));
2501 			return(TRUE);
2502 		}
2503 	}
2504 	return(FALSE);
2505 }
2506 
2507 /*
2508  * Helper routine to "xx()" for sorting samples by coordinate value.
2509  */
us_samplecoordascending(const void * e1,const void * e2)2510 int us_samplecoordascending(const void *e1, const void *e2)
2511 {
2512 	SAMPLE *s1, *s2;
2513 
2514 	s1 = *((SAMPLE **)e1);
2515 	s2 = *((SAMPLE **)e2);
2516 	if (s1->xpos != s2->xpos) return(s1->xpos - s2->xpos);
2517 	if (s1->ypos != s2->ypos) return(s1->ypos - s2->ypos);
2518 	return(s1->node->proto - s2->node->proto);
2519 }
2520 
2521 /* flags about the edge positions in the examples */
2522 #define TOEDGELEFT       01		/* constant to left edge */
2523 #define TOEDGERIGHT      02		/* constant to right edge */
2524 #define TOEDGETOP        04		/* constant to top edge */
2525 #define TOEDGEBOT       010		/* constant to bottom edge */
2526 #define FROMCENTX       020		/* constant in X to center */
2527 #define FROMCENTY       040		/* constant in Y to center */
2528 #define RATIOCENTX     0100		/* fixed ratio from X center to edge */
2529 #define RATIOCENTY     0200		/* fixed ratio from Y center to edge */
2530 
us_tecedmakeprim(EXAMPLE * nelist,NODEPROTO * np,TECHNOLOGY * tech,TECH_NODES * tlist,INTBIG lambda)2531 BOOLEAN us_tecedmakeprim(EXAMPLE *nelist, NODEPROTO *np, TECHNOLOGY *tech, TECH_NODES *tlist, INTBIG lambda)
2532 {
2533 	REGISTER SAMPLE *ns, *nso, *hs;
2534 	REGISTER EXAMPLE *ne;
2535 	REGISTER INTBIG total, count, newcount, i, truecount, multixs, multiys, multiindent, multisep;
2536 	REGISTER INTBIG *newrule, r, dist;
2537 	XARRAY trans;
2538 	REGISTER CHAR *str;
2539 	REGISTER VARIABLE *var, *var2, *var3;
2540 	REGISTER NODEINST *ni;
2541 
2542 	/* look at every sample "ns" in the main example "nelist" */
2543 	for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
2544 	{
2545 		/* ignore grab point specification */
2546 		if (ns->layer == gen_cellcenterprim) continue;
2547 
2548 		/* if there is only one example: make sample scale with edge */
2549 		if (nelist->nextexample == NOEXAMPLE)
2550 		{
2551 			/* if a multicut separation was given and this is a cut, add the rule */
2552 			if (tlist->f4 > 0 && ns->layer != NONODEPROTO && ns->layer != gen_portprim)
2553 			{
2554 				for(i=0; i<us_teclayer_count; i++)
2555 					if (namesame(us_teclayer_names[i], &ns->layer->protoname[6]) == 0) break;
2556 				if (i < us_teclayer_count)
2557 				{
2558 					if (layeriscontact(us_teclayer_function[i]))
2559 					{
2560 						hs = us_tecedneedhighlightlayer(nelist, np);
2561 						if (hs == 0) return(TRUE);
2562 						multixs = ns->node->highx - ns->node->lowx;
2563 						multiys = ns->node->highy - ns->node->lowy;
2564 						multiindent = ns->node->lowx - hs->node->lowx;
2565 						multisep = muldiv(tlist->f4, lambda, WHOLE);
2566 						ns->rule = us_tecedaddmulticutrule(multixs, multiys, multiindent, multisep);
2567 						if (ns->rule == 0) return(TRUE);
2568 						continue;
2569 					}
2570 				}
2571 			}
2572 
2573 			/* see if there is polygonal information */
2574 			if (ns->node->proto == art_filledpolygonprim ||
2575 				ns->node->proto == art_closedpolygonprim ||
2576 				ns->node->proto == art_openedpolygonprim ||
2577 				ns->node->proto == art_openeddottedpolygonprim ||
2578 				ns->node->proto == art_openeddashedpolygonprim ||
2579 				ns->node->proto == art_openedthickerpolygonprim)
2580 			{
2581 				var = gettrace(ns->node);
2582 			} else var = NOVARIABLE;
2583 			if (var != NOVARIABLE)
2584 			{
2585 				/* make sure the arrays hold "count" points */
2586 				count = getlength(var) / 2;
2587 				us_tecedforcearrays(count);
2588 
2589 				/* fill the array */
2590 				makerot(ns->node, trans);
2591 				for(i=0; i<count; i++)
2592 				{
2593 					xform((ns->node->geom->lowx + ns->node->geom->highx)/2 +
2594 						((INTBIG *)var->addr)[i*2],
2595 							(ns->node->geom->lowy + ns->node->geom->highy)/2 +
2596 								((INTBIG *)var->addr)[i*2+1], &us_tecedmakepx[i], &us_tecedmakepy[i], trans);
2597 					us_tecedmakefactor[i] = FROMCENTX|FROMCENTY;
2598 				}
2599 			} else
2600 			{
2601 				/* see if it is an arc of a circle */
2602 				count = 2;
2603 				if (ns->node->proto == art_circleprim || ns->node->proto == art_thickcircleprim)
2604 				{
2605 					var = getvalkey((INTBIG)ns->node, VNODEINST, VINTEGER, art_degreeskey);
2606 					if (var != NOVARIABLE) count = 3;
2607 				} else var = NOVARIABLE;
2608 
2609 				/* make sure the arrays hold enough points */
2610 				us_tecedforcearrays(count);
2611 
2612 				/* set sample description */
2613 				if (var != NOVARIABLE)
2614 				{
2615 					/* handle circular arc sample */
2616 					us_tecedmakepx[0] = (ns->node->geom->lowx + ns->node->geom->highx) / 2;
2617 					us_tecedmakepy[0] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2618 					makerot(ns->node, trans);
2619 					dist = ns->node->geom->highx - us_tecedmakepx[0];
2620 					xform(us_tecedmakepx[0] + mult(dist, cosine(var->addr)),
2621 						us_tecedmakepy[0] + mult(dist, sine(var->addr)), &us_tecedmakepx[1], &us_tecedmakepy[1], trans);
2622 					xform(ns->node->geom->highx,
2623 						(ns->node->geom->lowy + ns->node->geom->highy) / 2, &us_tecedmakepx[2], &us_tecedmakepy[2], trans);
2624 					us_tecedmakefactor[0] = FROMCENTX|FROMCENTY;
2625 					us_tecedmakefactor[1] = RATIOCENTX|RATIOCENTY;
2626 					us_tecedmakefactor[2] = RATIOCENTX|RATIOCENTY;
2627 				} else if (ns->node->proto == art_circleprim || ns->node->proto == art_thickcircleprim ||
2628 					ns->node->proto == art_filledcircleprim)
2629 				{
2630 					/* handle circular sample */
2631 					us_tecedmakepx[0] = (ns->node->geom->lowx + ns->node->geom->highx) / 2;
2632 					us_tecedmakepy[0] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2633 					us_tecedmakepx[1] = ns->node->geom->highx;
2634 					us_tecedmakepy[1] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2635 					us_tecedmakefactor[0] = FROMCENTX|FROMCENTY;
2636 					us_tecedmakefactor[1] = TOEDGERIGHT|FROMCENTY;
2637 				} else
2638 				{
2639 					/* rectangular sample: get the bounding box in (px, py) */
2640 					us_tecedgetbbox(ns->node, &us_tecedmakepx[0], &us_tecedmakepx[1], &us_tecedmakepy[0], &us_tecedmakepy[1]);
2641 
2642 					/* preset stretch factors to go to the edges of the box */
2643 					us_tecedmakefactor[0] = TOEDGELEFT|TOEDGEBOT;
2644 					us_tecedmakefactor[1] = TOEDGERIGHT|TOEDGETOP;
2645 				}
2646 			}
2647 
2648 			/* add the rule to the collection */
2649 			newrule = us_tecedstretchpoints(us_tecedmakepx,us_tecedmakepy, count, us_tecedmakefactor, ns, np,
2650 				nelist);
2651 			if (newrule == 0) return(TRUE);
2652 			var = getvalkey((INTBIG)ns->node, VNODEINST, VSTRING|VISARRAY, art_messagekey);
2653 			if (var == NOVARIABLE) str = (CHAR *)0; else
2654 				str = ((CHAR **)var->addr)[0];
2655 			ns->rule = us_tecedaddrule(newrule, count*4, FALSE, str);
2656 			if (ns->rule == NORULE) return(TRUE);
2657 			efree((CHAR *)newrule);
2658 			continue;
2659 		}
2660 
2661 		/* look at other examples and find samples associated with this */
2662 		nelist->studysample = ns;
2663 		for(ne = nelist->nextexample; ne != NOEXAMPLE; ne = ne->nextexample)
2664 		{
2665 			/* count number of samples associated with the main sample */
2666 			total = 0;
2667 			for(nso = ne->firstsample; nso != NOSAMPLE; nso = nso->nextsample)
2668 				if (nso->assoc == ns)
2669 			{
2670 				ne->studysample = nso;
2671 				total++;
2672 			}
2673 			if (total == 0)
2674 			{
2675 				us_tecedpointout(ns->node, ns->node->parent);
2676 				ttyputerr(_("Still unassociated sample in %s (shouldn't happen)"),
2677 					describenodeproto(np));
2678 				return(TRUE);
2679 			}
2680 
2681 			/* if there are multiple associations, it must be a contact cut */
2682 			if (total > 1)
2683 			{
2684 				/* make sure the layer is real geometry, not highlight or a port */
2685 				if (ns->layer == NONODEPROTO || ns->layer == gen_portprim)
2686 				{
2687 					us_tecedpointout(ns->node, ns->node->parent);
2688 					ttyputerr(_("Only contact layers may be iterated in examples of %s"),
2689 						describenodeproto(np));
2690 					return(TRUE);
2691 				}
2692 
2693 				/* make sure the contact cut layer is opaque */
2694 				for(i=0; i<tech->layercount; i++)
2695 					if (namesame(&ns->layer->protoname[6], us_teclayer_names[i]) == 0)
2696 				{
2697 					if (tech->layers[i]->bits != LAYERO)
2698 					{
2699 						us_tecedpointout(ns->node, ns->node->parent);
2700 						ttyputerr(_("Multiple contact layers must not be transparent in %s"),
2701 							describenodeproto(np));
2702 						return(TRUE);
2703 					}
2704 					break;
2705 				}
2706 
2707 				/* add the rule */
2708 				if (us_tecedmulticut(ns, nelist, np)) return(TRUE);
2709 				break;
2710 			}
2711 		}
2712 		if (ne != NOEXAMPLE) continue;
2713 
2714 		/* associations done for this sample, now analyze them */
2715 		if (ns->node->proto == art_filledpolygonprim ||
2716 			ns->node->proto == art_closedpolygonprim ||
2717 			ns->node->proto == art_openedpolygonprim ||
2718 			ns->node->proto == art_openeddottedpolygonprim ||
2719 			ns->node->proto == art_openeddashedpolygonprim ||
2720 			ns->node->proto == art_openedthickerpolygonprim)
2721 		{
2722 			var = gettrace(ns->node);
2723 		} else var = NOVARIABLE;
2724 		if (var != NOVARIABLE)
2725 		{
2726 			truecount = count = getlength(var) / 2;
2727 
2728 			/* make sure the arrays hold "count" points */
2729 			us_tecedforcearrays(count);
2730 			makerot(ns->node, trans);
2731 			for(i=0; i<count; i++)
2732 				xform((ns->node->geom->lowx + ns->node->geom->highx)/2 + ((INTBIG *)var->addr)[i*2],
2733 					(ns->node->geom->lowy + ns->node->geom->highy)/2 +
2734 						((INTBIG *)var->addr)[i*2+1], &us_tecedmakepx[i], &us_tecedmakepy[i], trans);
2735 		} else
2736 		{
2737 			/* make sure the arrays hold enough points */
2738 			count = 2;
2739 			if (ns->node->proto == art_circleprim || ns->node->proto == art_thickcircleprim)
2740 			{
2741 				var3 = getvalkey((INTBIG)ns->node, VNODEINST, VINTEGER, art_degreeskey);
2742 				if (var3 != NOVARIABLE) count = 3;
2743 			} else var3 = NOVARIABLE;
2744 			truecount = count;
2745 			if (var3 == NOVARIABLE)
2746 			{
2747 				var2 = getval((INTBIG)ns->node, VNODEINST, VSTRING, x_("EDTEC_minbox"));
2748 				if (var2 != NOVARIABLE) count *= 2;
2749 			}
2750 			us_tecedforcearrays(count);
2751 
2752 			/* set sample description */
2753 			if (var3 != NOVARIABLE)
2754 			{
2755 				/* handle circular arc sample */
2756 				us_tecedmakepx[0] = (ns->node->geom->lowx + ns->node->geom->highx) / 2;
2757 				us_tecedmakepy[0] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2758 				makerot(ns->node, trans);
2759 				dist = ns->node->geom->highx - us_tecedmakepx[0];
2760 				xform(us_tecedmakepx[0] + mult(dist, cosine(var3->addr)),
2761 					us_tecedmakepy[0] + mult(dist, sine(var3->addr)), &us_tecedmakepx[1], &us_tecedmakepy[1], trans);
2762 				xform(ns->node->geom->highx,
2763 					(ns->node->geom->lowy + ns->node->geom->highy) / 2, &us_tecedmakepx[2], &us_tecedmakepy[2], trans);
2764 			} else if (ns->node->proto == art_circleprim || ns->node->proto == art_thickcircleprim ||
2765 				ns->node->proto == art_filledcircleprim)
2766 			{
2767 				/* handle circular sample */
2768 				us_tecedmakepx[0] = (ns->node->geom->lowx + ns->node->geom->highx) / 2;
2769 				us_tecedmakepy[0] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2770 				us_tecedmakepx[1] = ns->node->geom->highx;
2771 				us_tecedmakepy[1] = (ns->node->geom->lowy + ns->node->geom->highy) / 2;
2772 			} else
2773 			{
2774 				/* rectangular sample: get the bounding box in (us_tecedmakepx, us_tecedmakepy) */
2775 				us_tecedgetbbox(ns->node, &us_tecedmakepx[0], &us_tecedmakepx[1], &us_tecedmakepy[0], &us_tecedmakepy[1]);
2776 			}
2777 			if (var2 != NOVARIABLE)
2778 			{
2779 				us_tecedmakepx[2] = us_tecedmakepx[0];   us_tecedmakepy[2] = us_tecedmakepy[0];
2780 				us_tecedmakepx[3] = us_tecedmakepx[1];   us_tecedmakepy[3] = us_tecedmakepy[1];
2781 			}
2782 		}
2783 
2784 		for(i=0; i<count; i++)
2785 		{
2786 			us_tecedmakeleftdist[i] = us_tecedmakepx[i] - nelist->lx;
2787 			us_tecedmakerightdist[i] = nelist->hx - us_tecedmakepx[i];
2788 			us_tecedmakebotdist[i] = us_tecedmakepy[i] - nelist->ly;
2789 			us_tecedmaketopdist[i] = nelist->hy - us_tecedmakepy[i];
2790 			us_tecedmakecentxdist[i] = us_tecedmakepx[i] - (nelist->lx+nelist->hx)/2;
2791 			us_tecedmakecentydist[i] = us_tecedmakepy[i] - (nelist->ly+nelist->hy)/2;
2792 			if (nelist->hx == nelist->lx) us_tecedmakeratiox[i] = 0; else
2793 				us_tecedmakeratiox[i] = (us_tecedmakepx[i] - (nelist->lx+nelist->hx)/2) * WHOLE / (nelist->hx-nelist->lx);
2794 			if (nelist->hy == nelist->ly) us_tecedmakeratioy[i] = 0; else
2795 				us_tecedmakeratioy[i] = (us_tecedmakepy[i] - (nelist->ly+nelist->hy)/2) * WHOLE / (nelist->hy-nelist->ly);
2796 			if (i < truecount)
2797 				us_tecedmakefactor[i] = TOEDGELEFT | TOEDGERIGHT | TOEDGETOP | TOEDGEBOT | FROMCENTX |
2798 					FROMCENTY | RATIOCENTX | RATIOCENTY; else
2799 						us_tecedmakefactor[i] = FROMCENTX | FROMCENTY;
2800 		}
2801 		for(ne = nelist->nextexample; ne != NOEXAMPLE; ne = ne->nextexample)
2802 		{
2803 			ni = ne->studysample->node;
2804 			if (ni->proto == art_filledpolygonprim ||
2805 				ni->proto == art_closedpolygonprim ||
2806 				ni->proto == art_openedpolygonprim ||
2807 				ni->proto == art_openeddottedpolygonprim ||
2808 				ni->proto == art_openeddashedpolygonprim ||
2809 				ni->proto == art_openedthickerpolygonprim)
2810 			{
2811 				var = gettrace(ni);
2812 			} else var = NOVARIABLE;
2813 			if (var != NOVARIABLE)
2814 			{
2815 				newcount = getlength(var) / 2;
2816 				makerot(ni, trans);
2817 				for(i=0; i<mini(truecount, newcount); i++)
2818 					xform((ni->geom->lowx + ni->geom->highx)/2 + ((INTBIG *)var->addr)[i*2],
2819 						(ni->geom->lowy + ni->geom->highy)/2 +
2820 							((INTBIG *)var->addr)[i*2+1], &us_tecedmakecx[i], &us_tecedmakecy[i], trans);
2821 			} else
2822 			{
2823 				newcount = 2;
2824 				if (ni->proto == art_circleprim || ni->proto == art_thickcircleprim)
2825 				{
2826 					var3 = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, art_degreeskey);
2827 					if (var3 != NOVARIABLE) newcount = 3;
2828 				} else var3 = NOVARIABLE;
2829 				if (var3 != NOVARIABLE)
2830 				{
2831 					us_tecedmakecx[0] = (ni->geom->lowx + ni->geom->highx) / 2;
2832 					us_tecedmakecy[0] = (ni->geom->lowy + ni->geom->highy) / 2;
2833 					makerot(ni, trans);
2834 					dist = ni->geom->highx - us_tecedmakecx[0];
2835 					xform(us_tecedmakecx[0] + mult(dist, cosine(var3->addr)),
2836 						us_tecedmakecy[0] + mult(dist, sine(var3->addr)), &us_tecedmakecx[1], &us_tecedmakecy[1], trans);
2837 					xform(ni->geom->highx, (ni->geom->lowy + ni->geom->highy) / 2,
2838 						&us_tecedmakecx[2], &us_tecedmakecy[2], trans);
2839 				} else if (ni->proto == art_circleprim || ni->proto == art_thickcircleprim ||
2840 					ni->proto == art_filledcircleprim)
2841 				{
2842 					us_tecedmakecx[0] = (ni->geom->lowx + ni->geom->highx) / 2;
2843 					us_tecedmakecy[0] = (ni->geom->lowy + ni->geom->highy) / 2;
2844 					us_tecedmakecx[1] = ni->geom->highx;
2845 					us_tecedmakecy[1] = (ni->geom->lowy + ni->geom->highy) / 2;
2846 				} else
2847 				{
2848 					us_tecedgetbbox(ni, &us_tecedmakecx[0], &us_tecedmakecx[1], &us_tecedmakecy[0], &us_tecedmakecy[1]);
2849 				}
2850 			}
2851 			if (newcount != truecount)
2852 			{
2853 				us_tecedpointout(ni, ni->parent);
2854 				ttyputerr(_("Main example of %s has %ld points but this has %ld in %s"),
2855 					us_tecedsamplename(ne->studysample->layer),
2856 						truecount, newcount, describenodeproto(np));
2857 				return(TRUE);
2858 			}
2859 
2860 			for(i=0; i<truecount; i++)
2861 			{
2862 				/* see if edges are fixed distance from example edge */
2863 				if (us_tecedmakeleftdist[i] != us_tecedmakecx[i] - ne->lx) us_tecedmakefactor[i] &= ~TOEDGELEFT;
2864 				if (us_tecedmakerightdist[i] != ne->hx - us_tecedmakecx[i]) us_tecedmakefactor[i] &= ~TOEDGERIGHT;
2865 				if (us_tecedmakebotdist[i] != us_tecedmakecy[i] - ne->ly) us_tecedmakefactor[i] &= ~TOEDGEBOT;
2866 				if (us_tecedmaketopdist[i] != ne->hy - us_tecedmakecy[i]) us_tecedmakefactor[i] &= ~TOEDGETOP;
2867 
2868 				/* see if edges are fixed distance from example center */
2869 				if (us_tecedmakecentxdist[i] != us_tecedmakecx[i] - (ne->lx+ne->hx)/2) us_tecedmakefactor[i] &= ~FROMCENTX;
2870 				if (us_tecedmakecentydist[i] != us_tecedmakecy[i] - (ne->ly+ne->hy)/2) us_tecedmakefactor[i] &= ~FROMCENTY;
2871 
2872 				/* see if edges are fixed ratio from example center */
2873 				if (ne->hx == ne->lx) r = 0; else
2874 					r = (us_tecedmakecx[i] - (ne->lx+ne->hx)/2) * WHOLE / (ne->hx-ne->lx);
2875 				if (r != us_tecedmakeratiox[i]) us_tecedmakefactor[i] &= ~RATIOCENTX;
2876 				if (ne->hy == ne->ly) r = 0; else
2877 					r = (us_tecedmakecy[i] - (ne->ly+ne->hy)/2) * WHOLE / (ne->hy-ne->ly);
2878 				if (r != us_tecedmakeratioy[i]) us_tecedmakefactor[i] &= ~RATIOCENTY;
2879 			}
2880 
2881 			/* make sure port information is on the primary example */
2882 			if (ns->layer != gen_portprim) continue;
2883 
2884 			/* check port angle */
2885 			var = getval((INTBIG)ns->node, VNODEINST, VINTEGER, x_("EDTEC_portangle"));
2886 			var2 = getval((INTBIG)ni, VNODEINST, VINTEGER, x_("EDTEC_portangle"));
2887 			if (var == NOVARIABLE && var2 != NOVARIABLE)
2888 			{
2889 				us_tecedpointout(NONODEINST, np);
2890 				ttyputerr(_("Warning: moving port angle to main example of %s"),
2891 					describenodeproto(np));
2892 				(void)setval((INTBIG)ns->node, VNODEINST, x_("EDTEC_portangle"), var2->addr, VINTEGER);
2893 			}
2894 
2895 			/* check port range */
2896 			var = getval((INTBIG)ns->node, VNODEINST, VINTEGER, x_("EDTEC_portrange"));
2897 			var2 = getval((INTBIG)ni, VNODEINST, VINTEGER, x_("EDTEC_portrange"));
2898 			if (var == NOVARIABLE && var2 != NOVARIABLE)
2899 			{
2900 				us_tecedpointout(NONODEINST, np);
2901 				ttyputerr(_("Warning: moving port range to main example of %s"), describenodeproto(np));
2902 				(void)setval((INTBIG)ns->node, VNODEINST, x_("EDTEC_portrange"), var2->addr, VINTEGER);
2903 			}
2904 
2905 			/* check connectivity */
2906 			var = getval((INTBIG)ns->node, VNODEINST, VNODEPROTO|VISARRAY, x_("EDTEC_connects"));
2907 			var2 = getval((INTBIG)ni, VNODEINST, VNODEPROTO|VISARRAY, x_("EDTEC_connects"));
2908 			if (var == NOVARIABLE && var2 != NOVARIABLE)
2909 			{
2910 				us_tecedpointout(NONODEINST, np);
2911 				ttyputerr(_("Warning: moving port connections to main example of %s"),
2912 					describenodeproto(np));
2913 				(void)setval((INTBIG)ns->node, VNODEINST, x_("EDTEC_connects"),
2914 					var2->addr, VNODEPROTO|VISARRAY|(getlength(var2)<<VLENGTHSH));
2915 			}
2916 		}
2917 
2918 		/* error check for the highlight layer */
2919 		if (ns->layer == NONODEPROTO)
2920 			for(i=0; i<truecount; i++)
2921 				if ((us_tecedmakefactor[i]&(TOEDGELEFT|TOEDGERIGHT)) == 0 ||
2922 					(us_tecedmakefactor[i]&(TOEDGETOP|TOEDGEBOT)) == 0)
2923 		{
2924 			us_tecedpointout(ns->node, ns->node->parent);
2925 			ttyputerr(_("Highlight must be constant distance from edge in %s"), describenodeproto(np));
2926 			return(TRUE);
2927 		}
2928 
2929 		/* finally, make a rule for this sample */
2930 		newrule = us_tecedstretchpoints(us_tecedmakepx, us_tecedmakepy, count, us_tecedmakefactor, ns, np, nelist);
2931 		if (newrule == 0) return(TRUE);
2932 
2933 		/* add the rule to the global list */
2934 		var = getvalkey((INTBIG)ns->node, VNODEINST, VSTRING|VISARRAY, art_messagekey);
2935 		if (var == NOVARIABLE) str = (CHAR *)0; else
2936 			str = ((CHAR **)var->addr)[0];
2937 		ns->rule = us_tecedaddrule(newrule, count*4, FALSE, str);
2938 		if (ns->rule == NORULE) return(TRUE);
2939 		efree((CHAR *)newrule);
2940 	}
2941 	return(FALSE);
2942 }
2943 
2944 /*
2945  * routine to ensure that the 13 global arrays are all at least "want" long.
2946  * Their current size is "us_tecedmakearrlen".
2947  */
us_tecedforcearrays(INTBIG want)2948 void us_tecedforcearrays(INTBIG want)
2949 {
2950 	if (us_tecedmakearrlen >= want) return;
2951 	if (us_tecedmakearrlen != 0)
2952 	{
2953 		efree((CHAR *)us_tecedmakepx);
2954 		efree((CHAR *)us_tecedmakepy);
2955 		efree((CHAR *)us_tecedmakecx);
2956 		efree((CHAR *)us_tecedmakecy);
2957 		efree((CHAR *)us_tecedmakefactor);
2958 		efree((CHAR *)us_tecedmakeleftdist);
2959 		efree((CHAR *)us_tecedmakerightdist);
2960 		efree((CHAR *)us_tecedmakebotdist);
2961 		efree((CHAR *)us_tecedmaketopdist);
2962 		efree((CHAR *)us_tecedmakecentxdist);
2963 		efree((CHAR *)us_tecedmakecentydist);
2964 		efree((CHAR *)us_tecedmakeratiox);
2965 		efree((CHAR *)us_tecedmakeratioy);
2966 	}
2967 	us_tecedmakearrlen = want;
2968 	us_tecedmakepx = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2969 	if (us_tecedmakepx == 0) return;
2970 	us_tecedmakepy = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2971 	if (us_tecedmakepy == 0) return;
2972 	us_tecedmakecx = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2973 	if (us_tecedmakecx == 0) return;
2974 	us_tecedmakecy = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2975 	if (us_tecedmakecy == 0) return;
2976 	us_tecedmakefactor = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2977 	if (us_tecedmakefactor == 0) return;
2978 	us_tecedmakeleftdist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2979 	if (us_tecedmakeleftdist == 0) return;
2980 	us_tecedmakerightdist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2981 	if (us_tecedmakerightdist == 0) return;
2982 	us_tecedmakebotdist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2983 	if (us_tecedmakebotdist == 0) return;
2984 	us_tecedmaketopdist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2985 	if (us_tecedmaketopdist == 0) return;
2986 	us_tecedmakecentxdist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2987 	if (us_tecedmakecentxdist == 0) return;
2988 	us_tecedmakecentydist = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2989 	if (us_tecedmakecentydist == 0) return;
2990 	us_tecedmakeratiox = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2991 	if (us_tecedmakeratiox == 0) return;
2992 	us_tecedmakeratioy = emalloc((want * SIZEOFINTBIG), us_tool->cluster);
2993 	if (us_tecedmakeratioy == 0) return;
2994 }
2995 
2996 /*
2997  * routine to adjust the "count"-long array of points in "px" and "py" according
2998  * to the stretch factor bits in "factor" and return an array that describes
2999  * these points.  Returns zero on error.
3000  */
us_tecedstretchpoints(INTBIG * px,INTBIG * py,INTBIG count,INTBIG * factor,SAMPLE * ns,NODEPROTO * np,EXAMPLE * nelist)3001 INTBIG *us_tecedstretchpoints(INTBIG *px, INTBIG *py, INTBIG count, INTBIG *factor,
3002 	SAMPLE *ns, NODEPROTO *np, EXAMPLE *nelist)
3003 {
3004 	REGISTER INTBIG *newrule, lambda;
3005 	REGISTER INTBIG i;
3006 
3007 	newrule = emalloc((count*4*SIZEOFINTBIG), el_tempcluster);
3008 	if (newrule == 0) return(0);
3009 
3010 	lambda = el_curlib->lambda[art_tech->techindex];
3011 	for(i=0; i<count; i++)
3012 	{
3013 		/* determine the X algorithm */
3014 		if ((factor[i]&TOEDGELEFT) != 0)
3015 		{
3016 			/* left edge rule */
3017 			newrule[i*4] = -H0;
3018 			newrule[i*4+1] = (px[i]-nelist->lx) * WHOLE/lambda;
3019 		} else if ((factor[i]&TOEDGERIGHT) != 0)
3020 		{
3021 			/* right edge rule */
3022 			newrule[i*4] = H0;
3023 			newrule[i*4+1] = (px[i]-nelist->hx) * WHOLE/lambda;
3024 		} else if ((factor[i]&FROMCENTX) != 0)
3025 		{
3026 			/* center rule */
3027 			newrule[i*4] = 0;
3028 			newrule[i*4+1] = (px[i]-(nelist->lx+nelist->hx)/2) * WHOLE/lambda;
3029 		} else if ((factor[i]&RATIOCENTX) != 0)
3030 		{
3031 			/* constant stretch rule */
3032 			if (nelist->hx == nelist->lx) newrule[i*4] = 0; else
3033 				newrule[i*4] = (px[i] - (nelist->lx+nelist->hx)/2) * WHOLE / (nelist->hx-nelist->lx);
3034 			newrule[i*4+1] = 0;
3035 		} else
3036 		{
3037 			us_tecedpointout(ns->node, ns->node->parent);
3038 			ttyputerr(_("Cannot determine X stretching rule for layer %s in %s"),
3039 				us_tecedsamplename(ns->layer), describenodeproto(np));
3040 			return(0);
3041 		}
3042 
3043 		/* determine the Y algorithm */
3044 		if ((factor[i]&TOEDGEBOT) != 0)
3045 		{
3046 			/* bottom edge rule */
3047 			newrule[i*4+2] = -H0;
3048 			newrule[i*4+3] = (py[i]-nelist->ly) * WHOLE/lambda;
3049 		} else if ((factor[i]&TOEDGETOP) != 0)
3050 		{
3051 			/* top edge rule */
3052 			newrule[i*4+2] = H0;
3053 			newrule[i*4+3] = (py[i]-nelist->hy) * WHOLE/lambda;
3054 		} else if ((factor[i]&FROMCENTY) != 0)
3055 		{
3056 			/* center rule */
3057 			newrule[i*4+2] = 0;
3058 			newrule[i*4+3] = (py[i]-(nelist->ly+nelist->hy)/2) * WHOLE/lambda;
3059 		} else if ((factor[i]&RATIOCENTY) != 0)
3060 		{
3061 			/* constant stretch rule */
3062 			if (nelist->hy == nelist->ly) newrule[i*4+2] = 0; else
3063 				newrule[i*4+2] = (py[i] - (nelist->ly+nelist->hy)/2) * WHOLE /
3064 					(nelist->hy-nelist->ly);
3065 			newrule[i*4+3] = 0;
3066 		} else
3067 		{
3068 			us_tecedpointout(ns->node, ns->node->parent);
3069 			ttyputerr(_("Cannot determine Y stretching rule for layer %s in %s"),
3070 				us_tecedsamplename(ns->layer), describenodeproto(np));
3071 			return(0);
3072 		}
3073 	}
3074 	return(newrule);
3075 }
3076 
us_tecedneedhighlightlayer(EXAMPLE * nelist,NODEPROTO * np)3077 SAMPLE *us_tecedneedhighlightlayer(EXAMPLE *nelist, NODEPROTO *np)
3078 {
3079 	REGISTER SAMPLE *hs;
3080 
3081 	/* find the highlight layer */
3082 	for(hs = nelist->firstsample; hs != NOSAMPLE; hs = hs->nextsample)
3083 		if (hs->layer == NONODEPROTO) return(hs);
3084 
3085 	us_tecedpointout(NONODEINST, np);
3086 	ttyputerr(_("No highlight layer on contact %s"), describenodeproto(np));
3087 	if ((us_tool->toolstate&NODETAILS) == 0)
3088 		ttyputmsg(_("Use 'place-layer' option to create HIGHLIGHT"));
3089 	return(0);
3090 }
3091 
3092 /*
3093  * routine to build a rule for multiple contact-cut sample "ns" from the
3094  * overall example list in "nelist".  Returns true on error.
3095  */
us_tecedmulticut(SAMPLE * ns,EXAMPLE * nelist,NODEPROTO * np)3096 BOOLEAN us_tecedmulticut(SAMPLE *ns, EXAMPLE *nelist, NODEPROTO *np)
3097 {
3098 	REGISTER INTBIG total, i, multixs, multiys, multiindent, multisep;
3099 	REGISTER INTBIG xsep, ysep, sepx, sepy;
3100 	REGISTER SAMPLE **nslist, *nso, *hs;
3101 	REGISTER EXAMPLE *ne;
3102 
3103 	/* find the highlight layer */
3104 	hs = us_tecedneedhighlightlayer(nelist, np);
3105 	if (hs == 0) return(TRUE);
3106 
3107 	/* determine size of each cut */
3108 	multixs = ns->node->highx - ns->node->lowx;
3109 	multiys = ns->node->highy - ns->node->lowy;
3110 
3111 	/* determine indentation of cuts */
3112 	multiindent = ns->node->lowx - hs->node->lowx;
3113 	if (hs->node->highx - ns->node->highx != multiindent ||
3114 		ns->node->lowy - hs->node->lowy != multiindent ||
3115 		hs->node->highy - ns->node->highy != multiindent)
3116 	{
3117 		us_tecedpointout(ns->node, ns->node->parent);
3118 		ttyputerr(_("Multiple contact cuts must be indented uniformly in %s"),
3119 			describenodeproto(np));
3120 		return(TRUE);
3121 	}
3122 
3123 	/* look at every example after the first */
3124 	xsep = ysep = -1;
3125 	for(ne = nelist->nextexample; ne != NOEXAMPLE; ne = ne->nextexample)
3126 	{
3127 		/* count number of samples equivalent to the main sample */
3128 		total = 0;
3129 		for(nso = ne->firstsample; nso != NOSAMPLE; nso = nso->nextsample)
3130 			if (nso->assoc == ns)
3131 		{
3132 			/* make sure size is proper */
3133 			if (multixs != nso->node->highx - nso->node->lowx ||
3134 				multiys != nso->node->highy - nso->node->lowy)
3135 			{
3136 				us_tecedpointout(nso->node, nso->node->parent);
3137 				ttyputerr(_("Multiple contact cuts must not differ in size in %s"),
3138 					describenodeproto(np));
3139 				return(TRUE);
3140 			}
3141 			total++;
3142 		}
3143 
3144 		/* allocate space for these samples */
3145 		nslist = (SAMPLE **)emalloc((total * (sizeof (SAMPLE *))), el_tempcluster);
3146 		if (nslist == 0) return(TRUE);
3147 
3148 		/* fill the list of samples */
3149 		i = 0;
3150 		for(nso = ne->firstsample; nso != NOSAMPLE; nso = nso->nextsample)
3151 			if (nso->assoc == ns) nslist[i++] = nso;
3152 
3153 		/* analyze the samples for separation */
3154 		for(i=1; i<total; i++)
3155 		{
3156 			/* find separation */
3157 			sepx = abs((nslist[i-1]->node->highx + nslist[i-1]->node->lowx) / 2 -
3158 				(nslist[i]->node->highx + nslist[i]->node->lowx) / 2);
3159 			sepy = abs((nslist[i-1]->node->highy + nslist[i-1]->node->lowy) / 2 -
3160 				(nslist[i]->node->highy + nslist[i]->node->lowy) / 2);
3161 
3162 			/* check for validity */
3163 			if (sepx < multixs && sepy < multiys)
3164 			{
3165 				us_tecedpointout(nslist[i]->node, nslist[i]->node->parent);
3166 				ttyputerr(_("Multiple contact cuts must not overlap in %s"),
3167 					describenodeproto(np));
3168 				efree((CHAR *)nslist);
3169 				return(TRUE);
3170 			}
3171 
3172 			/* accumulate minimum separation */
3173 			if (sepx >= multixs)
3174 			{
3175 				if (xsep < 0) xsep = sepx; else
3176 				{
3177 					if (xsep > sepx) xsep = sepx;
3178 				}
3179 			}
3180 			if (sepy >= multiys)
3181 			{
3182 				if (ysep < 0) ysep = sepy; else
3183 				{
3184 					if (ysep > sepy) ysep = sepy;
3185 				}
3186 			}
3187 		}
3188 
3189 		/* finally ensure that all separations are multiples of "multisep" */
3190 		for(i=1; i<total; i++)
3191 		{
3192 			/* find X separation */
3193 			sepx = abs((nslist[i-1]->node->highx + nslist[i-1]->node->lowx) / 2 -
3194 				(nslist[i]->node->highx + nslist[i]->node->lowx) / 2);
3195 			sepy = abs((nslist[i-1]->node->highy + nslist[i-1]->node->lowy) / 2 -
3196 				(nslist[i]->node->highy + nslist[i]->node->lowy) / 2);
3197 			if (sepx / xsep * xsep != sepx)
3198 			{
3199 				us_tecedpointout(nslist[i]->node, nslist[i]->node->parent);
3200 				ttyputerr(_("Multiple contact cut X spacing must be uniform in %s"),
3201 					describenodeproto(np));
3202 				efree((CHAR *)nslist);
3203 				return(TRUE);
3204 			}
3205 
3206 			/* find Y separation */
3207 			if (sepy / ysep * ysep != sepy)
3208 			{
3209 				us_tecedpointout(nslist[i]->node, nslist[i]->node->parent);
3210 				ttyputerr(_("Multiple contact cut Y spacing must be uniform in %s"),
3211 					describenodeproto(np));
3212 				efree((CHAR *)nslist);
3213 				return(TRUE);
3214 			}
3215 		}
3216 		efree((CHAR *)nslist);
3217 	}
3218 	multisep = xsep - multixs;
3219 	if (multisep != ysep - multiys)
3220 	{
3221 		us_tecedpointout(NONODEINST, np);
3222 		ttyputerr(_("Multiple contact cut X and Y spacing must be the same in %s"),
3223 			describenodeproto(np));
3224 		return(TRUE);
3225 	}
3226 	ns->rule = us_tecedaddmulticutrule(multixs, multiys, multiindent, multisep);
3227 	if (ns->rule == 0) return(TRUE);
3228 	return(FALSE);
3229 }
3230 
us_tecedaddmulticutrule(INTBIG multixs,INTBIG multiys,INTBIG multiindent,INTBIG multisep)3231 RULE *us_tecedaddmulticutrule(INTBIG multixs, INTBIG multiys, INTBIG multiindent, INTBIG multisep)
3232 {
3233 	REGISTER RULE *rule;
3234 	INTBIG rulearr[8];
3235 
3236 	rulearr[0] = -H0;   rulearr[1] = K1;
3237 	rulearr[2] = -H0;   rulearr[3] = K1;
3238 	rulearr[4] = -H0;   rulearr[5] = K3;
3239 	rulearr[6] = -H0;   rulearr[7] = K3;
3240 	rule = us_tecedaddrule(rulearr, 8, TRUE, (CHAR *)0);
3241 	if (rule == NORULE) return(0);
3242 	rule->multixs = multixs;
3243 	rule->multiys = multiys;
3244 	rule->multiindent = multiindent;
3245 	rule->multisep = multisep;
3246 	return(rule);
3247 }
3248 
3249 /*
3250  * routine to add the "len"-long list of port connections in "conlist" to
3251  * the list of port connections, and return the port connection entry
3252  * for this one.  Returns NOPCON on error
3253  */
us_tecedaddportlist(INTBIG len,INTBIG * conlist)3254 PCON *us_tecedaddportlist(INTBIG len, INTBIG *conlist)
3255 {
3256 	REGISTER PCON *pc;
3257 	REGISTER INTBIG i, j;
3258 
3259 	/* find a port connection that is the same */
3260 	for(pc = us_tecedfirstpcon; pc != NOPCON; pc = pc->nextpcon)
3261 	{
3262 		if (pc->total != len) continue;
3263 		for(j=0; j<pc->total; j++) pc->assoc[j] = 0;
3264 		for(i=0; i<len; i++)
3265 		{
3266 			for(j=0; j<pc->total; j++) if (pc->connects[j+1] == conlist[i])
3267 			{
3268 				pc->assoc[j]++;
3269 				break;
3270 			}
3271 		}
3272 		for(j=0; j<pc->total; j++) if (pc->assoc[j] == 0) break;
3273 		if (j >= pc->total) return(pc);
3274 	}
3275 
3276 	/* not found: add to list */
3277 	pc = (PCON *)emalloc((sizeof (PCON)), us_tool->cluster);
3278 	if (pc == 0) return(NOPCON);
3279 	pc->total = len;
3280 	pc->connects = emalloc(((len+5)*SIZEOFINTBIG), us_tool->cluster);
3281 	if (pc->connects == 0) return(NOPCON);
3282 	pc->assoc = emalloc((len*SIZEOFINTBIG), us_tool->cluster);
3283 	if (pc->assoc == 0) return(NOPCON);
3284 	for(j=0; j<len; j++) pc->connects[j+1] = conlist[j];
3285 	pc->connects[0] = -1;
3286 	pc->connects[len+1] = AUNIV;
3287 	pc->connects[len+2] = AINVIS;
3288 	pc->connects[len+3] = AUNROUTED;
3289 	pc->connects[len+4] = -1;
3290 	pc->nextpcon = us_tecedfirstpcon;
3291 	us_tecedfirstpcon = pc;
3292 	return(pc);
3293 }
3294 
3295 /*
3296  * routine to get the list of libraries that are used in the construction
3297  * of library "lib".  Returns the number of libraries, terminated with "lib",
3298  * and sets the list in "liblist".
3299  */
us_teceditgetdependents(LIBRARY * lib,LIBRARY *** liblist)3300 INTBIG us_teceditgetdependents(LIBRARY *lib, LIBRARY ***liblist)
3301 {
3302 	REGISTER VARIABLE *var;
3303 	REGISTER INTBIG i, j, total;
3304 	REGISTER CHAR *pt;
3305 
3306 	/* get list of dependent libraries */
3307 	var = getval((INTBIG)lib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_dependent_libraries"));
3308 	if (var == NOVARIABLE) j = 0; else j = getlength(var);
3309 	if (j >= us_teceddepliblistsize)
3310 	{
3311 		if (us_teceddepliblistsize != 0) efree((CHAR *)us_teceddepliblist);
3312 		us_teceddepliblist = (LIBRARY **)emalloc((j+1) * (sizeof (LIBRARY *)), us_tool->cluster);
3313 		if (us_teceddepliblist == 0) return(0);
3314 		us_teceddepliblistsize = j+1;
3315 	}
3316 
3317 	total = 0;
3318 	for(i=0; i<j; i++)
3319 	{
3320 		pt = ((CHAR **)var->addr)[i];
3321 		us_teceddepliblist[total++] = getlibrary(pt);
3322 		if (us_teceddepliblist[total-1] == NOLIBRARY)
3323 		{
3324 			ttyputerr(_("Cannot find dependent technology library %s, ignoring"), pt);
3325 			total--;
3326 			continue;
3327 		}
3328 		if (us_teceddepliblist[total-1] == lib)
3329 		{
3330 			ttyputerr(_("Library cannot depend on itself, ignoring dependency"));
3331 			total--;
3332 			continue;
3333 		}
3334 	}
3335 	us_teceddepliblist[total++] = lib;
3336 	*liblist = us_teceddepliblist;
3337 	return(total);
3338 }
3339 
3340 /*
3341  * general-purpose routine to scan the "dependentlibcount" libraries in "dependentlibs",
3342  * looking for cells that begin with the string "match".  It then uses the
3343  * variable "seqname" on the last library to determine an ordering of the cells.
3344  * Then, it returns the cells in the array "sequence" and returns the number of them.
3345  * Returns 0 on error.
3346  */
us_teceditfindsequence(LIBRARY ** dependentlibs,INTBIG dependentlibcount,CHAR * match,CHAR * seqname,NODEPROTO *** sequence)3347 INTBIG us_teceditfindsequence(LIBRARY **dependentlibs, INTBIG dependentlibcount,
3348 	CHAR *match, CHAR *seqname, NODEPROTO ***sequence)
3349 {
3350 	REGISTER INTBIG total;
3351 	REGISTER INTBIG i, j, k, l, npsize, matchcount;
3352 	REGISTER NODEPROTO *np, *lnp, **nplist, **newnplist;
3353 	REGISTER VARIABLE *var;
3354 	REGISTER LIBRARY *olderlib, *laterlib;
3355 
3356 	/* look backwards through libraries for the appropriate cells */
3357 	matchcount = estrlen(match);
3358 	total = 0;
3359 	npsize = 0;
3360 	for(i=dependentlibcount-1; i>=0; i--)
3361 	{
3362 		olderlib = dependentlibs[i];
3363 		for(np = olderlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3364 			if (namesamen(np->protoname, match, matchcount) == 0)
3365 		{
3366 			/* see if this cell is used in a later library */
3367 			for(j=i+1; j<dependentlibcount; j++)
3368 			{
3369 				laterlib = dependentlibs[j];
3370 				for(lnp = laterlib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
3371 					if (namesame(lnp->protoname, np->protoname) == 0)
3372 				{
3373 					/* got older and later version of same cell: check dates */
3374 					if (lnp->revisiondate < np->revisiondate)
3375 						ttyputmsg(_("Warning: library %s has newer %s than library %s"),
3376 							olderlib->libname, np->protoname, laterlib->libname);
3377 					break;
3378 				}
3379 				if (lnp != NONODEPROTO) break;
3380 			}
3381 
3382 			/* if no later library has this, add to total */
3383 			if (j >= dependentlibcount)
3384 			{
3385 				if (total >= npsize)
3386 				{
3387 					newnplist = (NODEPROTO **)emalloc((npsize+10) * (sizeof (NODEPROTO *)),
3388 						el_tempcluster);
3389 					if (newnplist == 0) return(0);
3390 
3391 					/* LINTED "nplist" used in proper order */
3392 					for(k=0; k<total; k++) newnplist[k] = nplist[k];
3393 					if (npsize != 0) efree((CHAR *)nplist);
3394 					nplist = newnplist;
3395 					npsize += 10;
3396 				}
3397 				newnplist[total++] = np;
3398 			}
3399 		}
3400 	}
3401 	if (total <= 0) return(0);
3402 
3403 	/* if there is no sequence, simply return the list */
3404 	var = getval((INTBIG)dependentlibs[dependentlibcount-1], VLIBRARY, VSTRING|VISARRAY, seqname);
3405 	if (var == NOVARIABLE)
3406 	{
3407 		*sequence = nplist;
3408 		return(total);
3409 	}
3410 
3411 	/* allocate a new list to be built from the sequence */
3412 	*sequence = (NODEPROTO **)emalloc(total * (sizeof (NODEPROTO *)), el_tempcluster);
3413 	if (*sequence == 0) return(0);
3414 
3415 	j = getlength(var);
3416 	k = 0;
3417 	for(i=0; i<j; i++)
3418 	{
3419 		for(l = 0; l < total; l++)
3420 		{
3421 			np = nplist[l];
3422 			if (np == NONODEPROTO) continue;
3423 			if (namesame(&np->protoname[matchcount], ((CHAR **)var->addr)[i]) == 0) break;
3424 		}
3425 		if (l >= total) continue;
3426 		(*sequence)[k++] = np;
3427 		nplist[l] = NONODEPROTO;
3428 	}
3429 	for(l = 0; l < total; l++)
3430 	{
3431 		np = nplist[l];
3432 		if (np != NONODEPROTO) (*sequence)[k++] = np;
3433 	}
3434 	efree((CHAR *)nplist);
3435 	return(total);
3436 }
3437 
us_tecedaddrule(INTBIG list[8],INTBIG count,BOOLEAN multcut,CHAR * istext)3438 RULE *us_tecedaddrule(INTBIG list[8], INTBIG count, BOOLEAN multcut, CHAR *istext)
3439 {
3440 	REGISTER RULE *r;
3441 	REGISTER INTBIG i, textinc;
3442 
3443 	for(r = us_tecedfirstrule; r != NORULE; r = r->nextrule)
3444 	{
3445 		if (multcut != r->multicut) continue;
3446 		if (istext != 0 && r->istext != 0)
3447 		{
3448 			if (namesame(istext, (CHAR *)r->value[count]) != 0) continue;
3449 		} else if (istext != 0 || r->istext != 0) continue;
3450 		if (count != r->count) continue;
3451 		for(i=0; i<count; i++) if (r->value[i] != list[i]) break;
3452 		if (i >= count) return(r);
3453 	}
3454 
3455 	r = (RULE *)emalloc((sizeof (RULE)), us_tool->cluster);
3456 	if (r == 0) return(NORULE);
3457 	if (istext != 0) textinc = 1; else textinc = 0;
3458 	r->value = emalloc(((count+textinc) * SIZEOFINTBIG), us_tool->cluster);
3459 	if (r->value == 0) return(NORULE);
3460 	r->count = count;
3461 	r->nextrule = us_tecedfirstrule;
3462 	r->used = FALSE;
3463 	r->multicut = multcut;
3464 	us_tecedfirstrule = r;
3465 	for(i=0; i<count; i++) r->value[i] = list[i];
3466 	r->istext = 0;
3467 	if (istext != 0)
3468 	{
3469 		(void)allocstring((CHAR **)(&r->value[count]), istext, us_tool->cluster);
3470 		r->istext = 1;
3471 	}
3472 	return(r);
3473 }
3474 
3475 /*
3476  * Routine to obtain the layer associated with node "ni".  Returns 0 if the layer is not
3477  * there or invalid.  Returns NONODEPROTO if this is the highlight layer.
3478  */
us_tecedgetlayer(NODEINST * ni)3479 NODEPROTO *us_tecedgetlayer(NODEINST *ni)
3480 {
3481 	REGISTER VARIABLE *var;
3482 	REGISTER NODEPROTO *np, *onp;
3483 
3484 	var = getval((INTBIG)ni, VNODEINST, VNODEPROTO, x_("EDTEC_layer"));
3485 	if (var == NOVARIABLE) return(0);
3486 	np = (NODEPROTO *)var->addr;
3487 	if (np != NONODEPROTO)
3488 	{
3489 		/* validate the reference */
3490 		for(onp = ni->parent->lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3491 			if (onp == np) break;
3492 		if (onp == NONODEPROTO) return(0);
3493 	}
3494 	return(np);
3495 }
3496 
3497 /****************************** WRITE TECHNOLOGY AS "C" CODE ******************************/
3498 
3499 /*
3500  * routine to dump the layer information in technology "tech" to the stream in
3501  * "f".
3502  */
us_teceditdumplayers(FILE * f,TECHNOLOGY * tech,CHAR * techname)3503 void us_teceditdumplayers(FILE *f, TECHNOLOGY *tech, CHAR *techname)
3504 {
3505 	CHAR *sym, *colorname, *colorsymbol, date[30];
3506 	REGISTER INTBIG i, j, k, l;
3507 	REGISTER CHAR *l1, *l2, *l3, *l4, *l5;
3508 	REGISTER void *infstr;
3509 
3510 	/* write information for "tectable.c" */
3511 	xprintf(f, x_("#if 0\n"));
3512 	xprintf(f, _("/* the next 4 lines belong at the top of 'tectable.c': */\n"));
3513 	xprintf(f, x_("extern GRAPHICS *%s_layers[];\n"), us_tecedmakesymbol(techname));
3514 	xprintf(f, x_("extern TECH_ARCS *%s_arcprotos[];\n"), us_tecedmakesymbol(techname));
3515 	xprintf(f, x_("extern TECH_NODES *%s_nodeprotos[];\n"), us_tecedmakesymbol(techname));
3516 	xprintf(f, x_("extern TECH_VARIABLES %s_variables[];\n"), us_tecedmakesymbol(techname));
3517 	xprintf(f, x_("\n/* the next 8 lines belong in the 'el_technologylist' array of 'tectable.c': */\n"));
3518 	xprintf(f, x_("\t{x_(\"%s\"), 0, %ld, NONODEPROTO,NOARCPROTO,NOVARIABLE,0,NOCOMCOMP,NOCLUSTER,\t/* info */\n"),
3519 		us_tecedmakesymbol(techname), tech->deflambda);
3520 	xprintf(f, x_("\tN_(\"%s\"),\t/* description */\n"), tech->techdescript);
3521 	xprintf(f, x_("\t0, %s_layers,"), us_tecedmakesymbol(techname));
3522 	xprintf(f, x_(" 0, %s_arcprotos,"), us_tecedmakesymbol(techname));
3523 	xprintf(f, x_(" 0, %s_nodeprotos,"), us_tecedmakesymbol(techname));
3524 	xprintf(f, x_(" %s_variables,\t/* tables */\n"), us_tecedmakesymbol(techname));
3525 	xprintf(f, x_("\t0, 0, 0, 0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* control routines */\n"));
3526 	xprintf(f, x_("\t0, 0, 0, 0, 0, 0, 0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* node routines */\n"));
3527 	xprintf(f, x_("\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* port routine */\n"));
3528 	xprintf(f, x_("\t0, 0, 0, 0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* arc routines */\n"));
3529 	xprintf(f, x_("\tNOTECHNOLOGY, NONEGATEDARCS|STATICTECHNOLOGY, 0, 0},\t\t\t\t\t\t\t/* miscellaneous */\n"));
3530 	xprintf(f, x_("#endif\n"));
3531 
3532 	/* write legal banner */
3533 	xprintf(f, x_("/*\n"));
3534 	xprintf(f, x_(" * Electric(tm) VLSI Design System\n"));
3535 	xprintf(f, x_(" *\n"));
3536 	xprintf(f, x_(" * File: %s.c\n"), techname);
3537 	xprintf(f, x_(" * %s technology description\n"), techname);
3538 	xprintf(f, x_(" * Generated automatically from a library\n"));
3539 	xprintf(f, x_(" *\n"));
3540 	estrcpy(date, timetostring(getcurrenttime()));
3541 	date[24] = 0;
3542 	xprintf(f, x_(" * Copyright (c) %s Static Free Software.\n"), &date[20]);
3543 	xprintf(f, x_(" *\n"));
3544 	xprintf(f, x_(" * Electric(tm) is free software; you can redistribute it and/or modify\n"));
3545 	xprintf(f, x_(" * it under the terms of the GNU General Public License as published by\n"));
3546 	xprintf(f, x_(" * the Free Software Foundation; either version 2 of the License, or\n"));
3547 	xprintf(f, x_(" * (at your option) any later version.\n"));
3548 	xprintf(f, x_(" *\n"));
3549 	xprintf(f, x_(" * Electric(tm) is distributed in the hope that it will be useful,\n"));
3550 	xprintf(f, x_(" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"));
3551 	xprintf(f, x_(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"));
3552 	xprintf(f, x_(" * GNU General Public License for more details.\n"));
3553 	xprintf(f, x_(" *\n"));
3554 	xprintf(f, x_(" * You should have received a copy of the GNU General Public License\n"));
3555 	xprintf(f, x_(" * along with Electric(tm); see the file COPYING.  If not, write to\n"));
3556 	xprintf(f, x_(" * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,\n"));
3557 	xprintf(f, x_(" * Boston, Mass 02111-1307, USA.\n"));
3558 	xprintf(f, x_(" *\n"));
3559 	xprintf(f, x_(" * Static Free Software\n"));
3560 	xprintf(f, x_(" * 4119 Alpine Road\n"));
3561 	xprintf(f, x_(" * Portola Valley, California 94028\n"));
3562 	xprintf(f, x_(" * info@staticfreesoft.com\n"));
3563 	xprintf(f, x_(" */\n"));
3564 
3565 	/* write header */
3566 	xprintf(f, x_("#include \"global.h\"\n"));
3567 	xprintf(f, x_("#include \"egraphics.h\"\n"));
3568 	xprintf(f, x_("#include \"tech.h\"\n"));
3569 	xprintf(f, x_("#include \"efunction.h\"\n"));
3570 
3571 	/* write the layer declarations */
3572 	xprintf(f, x_("\n/******************** LAYERS ********************/\n"));
3573 	k = 8;
3574 	for(i=0; i<tech->layercount; i++) k = maxi(k, estrlen(us_teclayer_iname[i]));
3575 	k++;
3576 	xprintf(f, x_("\n#define MAXLAYERS"));
3577 	for(j=8; j<k; j++) xprintf(f, x_(" "));
3578 	xprintf(f, x_("%ld\n"), tech->layercount);
3579 	for(i=0; i<tech->layercount; i++)
3580 	{
3581 		xprintf(f, x_("#define L%s"), us_teclayer_iname[i]);
3582 		for(j=estrlen(us_teclayer_iname[i]); j<k; j++) xprintf(f, x_(" "));
3583 		xprintf(f, x_("%ld\t\t\t\t/* %s */\n"), i, us_teclayer_names[i]);
3584 	}
3585 	xprintf(f, x_("\n"));
3586 
3587 	/* write the layer descriptions */
3588 	for(i=0; i<tech->layercount; i++)
3589 	{
3590 		xprintf(f, x_("static GRAPHICS %s_%s_lay = {"), us_tecedmakesymbol(techname),
3591 			us_teclayer_iname[i]);
3592 		switch (tech->layers[i]->bits)
3593 		{
3594 			case LAYERT1: xprintf(f, x_("LAYERT1, "));   break;
3595 			case LAYERT2: xprintf(f, x_("LAYERT2, "));   break;
3596 			case LAYERT3: xprintf(f, x_("LAYERT3, "));   break;
3597 			case LAYERT4: xprintf(f, x_("LAYERT4, "));   break;
3598 			case LAYERT5: xprintf(f, x_("LAYERT5, "));   break;
3599 			case LAYERO:  xprintf(f, x_("LAYERO, "));    break;
3600 		}
3601 		if (ecolorname(tech->layers[i]->col, &colorname, &colorsymbol)) colorsymbol = x_("unknown");
3602 		xprintf(f, x_("%s, "), colorsymbol);
3603 		if ((tech->layers[i]->colstyle&NATURE) == SOLIDC) xprintf(f, x_("SOLIDC")); else
3604 		{
3605 			xprintf(f, x_("PATTERNED"));
3606 			if ((tech->layers[i]->colstyle&OUTLINEPAT) != 0) xprintf(f, x_("|OUTLINEPAT"));
3607 		}
3608 		xprintf(f, x_(", "));
3609 		if ((tech->layers[i]->bwstyle&NATURE) == SOLIDC) xprintf(f, x_("SOLIDC")); else
3610 		{
3611 			xprintf(f, x_("PATTERNED"));
3612 			if ((tech->layers[i]->bwstyle&OUTLINEPAT) != 0) xprintf(f, x_("|OUTLINEPAT"));
3613 		}
3614 		xprintf(f, x_(","));
3615 
3616 		xprintf(f, x_("\n"));
3617 		for(j=0; j<16; j++) if (tech->layers[i]->raster[j] != 0) break;
3618 		if (j >= 16)
3619 			xprintf(f, x_("\t{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, NOVARIABLE, 0};\n")); else
3620 		{
3621 			for(j=0; j<16; j++)
3622 			{
3623 				xprintf(f, x_("\t"));
3624 				if (j == 0) xprintf(f, x_("{"));
3625 				xprintf(f, x_("0x%04x"), tech->layers[i]->raster[j]&0xFFFF);
3626 				if (j == 15) xprintf(f, x_("}"));
3627 				xprintf(f, x_(","));
3628 				if (j > 0 && j < 15) xprintf(f, x_(" "));
3629 				xprintf(f, x_("  /* "));
3630 				for(k=0; k<16; k++)
3631 					if ((tech->layers[i]->raster[j] & (1 << (15-k))) != 0)
3632 						xprintf(f, x_("X")); else xprintf(f, x_(" "));
3633 				xprintf(f, x_(" */\n"));
3634 			}
3635 			xprintf(f, x_("\tNOVARIABLE, 0};\n"));
3636 		}
3637 	}
3638 
3639 	/* write the aggregation of all layers */
3640 	sym = us_tecedmakesymbol(techname);
3641 	xprintf(f, x_("\nGRAPHICS *%s_layers[MAXLAYERS+1] = {\n"), sym);
3642 	for(i=0; i<tech->layercount; i++)
3643 	{
3644 		xprintf(f, x_("\t&%s_%s_lay,"), sym, us_teclayer_iname[i]);
3645 		xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3646 	}
3647 	xprintf(f, x_("\tNOGRAPHICS\n};\n"));
3648 
3649 	/* write the layer names */
3650 	sym = us_tecedmakesymbol(techname);
3651 	l = estrlen(sym) + 40;
3652 	xprintf(f, x_("static char *%s_layer_names[MAXLAYERS] = {"), sym);
3653 	for(i=0; i<tech->layercount; i++)
3654 	{
3655 		if (i != 0) { xprintf(f, x_(", ")); l += 2; }
3656 		if (us_teclayer_names[i] == 0) sym = x_(""); else sym = us_teclayer_names[i];
3657 		if (l + estrlen(sym) + 2 > 80)
3658 		{
3659 			xprintf(f, x_("\n\t"));
3660 			l = 4;
3661 		}
3662 		xprintf(f, x_("x_(\"%s\")"), sym);
3663 		l += estrlen(sym) + 2;
3664 	}
3665 	xprintf(f, x_("};\n"));
3666 
3667 	/* write the CIF layer names */
3668 	if ((us_tecflags&HASCIF) != 0)
3669 	{
3670 		xprintf(f, x_("static char *%s_cif_layers[MAXLAYERS] = {\n"), us_tecedmakesymbol(techname));
3671 		for(i=0; i<tech->layercount; i++)
3672 		{
3673 			if (us_teccif_layers[i] == 0) xprintf(f, x_("\tx_(\"\")")); else
3674 				xprintf(f, x_("\tx_(\"%s\")"), us_teccif_layers[i]);
3675 			if (i != tech->layercount-1) xprintf(f, x_(","));
3676 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3677 		}
3678 		xprintf(f, x_("};\n"));
3679 	}
3680 
3681 	/* write the DXF layer numbers */
3682 	if ((us_tecflags&HASDXF) != 0)
3683 	{
3684 		xprintf(f, x_("static char *%s_dxf_layers[MAXLAYERS] = {\n"), us_tecedmakesymbol(techname));
3685 		for(i=0; i<tech->layercount; i++)
3686 		{
3687 			xprintf(f, x_("\tx_(\"%s\")"), us_tecdxf_layers[i]);
3688 			if (i != tech->layercount-1) xprintf(f, x_(","));
3689 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3690 		}
3691 		xprintf(f, x_("};\n"));
3692 	}
3693 
3694 	/* write the Calma GDS-II layer number */
3695 	if ((us_tecflags&HASGDS) != 0)
3696 	{
3697 		xprintf(f, x_("static CHAR *%s_gds_layers[MAXLAYERS] = {\n"), us_tecedmakesymbol(techname));
3698 		for(i=0; i<tech->layercount; i++)
3699 		{
3700 			xprintf(f, x_("\tx_(\"%s\")"), us_tecgds_layers[i]);
3701 			if (i != tech->layercount-1) xprintf(f, x_(","));
3702 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3703 		}
3704 		xprintf(f, x_("};\n"));
3705 	}
3706 
3707 	/* write the layer functions */
3708 	xprintf(f, x_("static INTBIG %s_layer_function[MAXLAYERS] = {\n"), us_tecedmakesymbol(techname));
3709 	for(i=0; i<tech->layercount; i++)
3710 	{
3711 		infstr = initinfstr();
3712 		addstringtoinfstr(infstr, us_teclayer_functions[us_teclayer_function[i]&LFTYPE].constant);
3713 		for(j=0; us_teclayer_functions[j].name != 0; j++)
3714 		{
3715 			if (us_teclayer_functions[j].value <= LFTYPE) continue;
3716 			if ((us_teclayer_function[i]&us_teclayer_functions[j].value) != 0)
3717 			{
3718 				addtoinfstr(infstr, '|');
3719 				addstringtoinfstr(infstr, us_teclayer_functions[j].constant);
3720 			}
3721 		}
3722 		if (tech->layers[i]->bits == LAYERT1) addstringtoinfstr(infstr, x_("|LFTRANS1")); else
3723 		if (tech->layers[i]->bits == LAYERT2) addstringtoinfstr(infstr, x_("|LFTRANS2")); else
3724 		if (tech->layers[i]->bits == LAYERT3) addstringtoinfstr(infstr, x_("|LFTRANS3")); else
3725 		if (tech->layers[i]->bits == LAYERT4) addstringtoinfstr(infstr, x_("|LFTRANS4")); else
3726 		if (tech->layers[i]->bits == LAYERT5) addstringtoinfstr(infstr, x_("|LFTRANS5"));
3727 		xprintf(f, x_("\t%s"), returninfstr(infstr));
3728 		if (i != tech->layercount-1) xprintf(f, x_(","));
3729 		xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3730 	}
3731 	xprintf(f, x_("};\n"));
3732 
3733 	/* write the layer letters */
3734 	xprintf(f, x_("static char *%s_layer_letters[MAXLAYERS] = {\n"), us_tecedmakesymbol(techname));
3735 	for(i=0; i<tech->layercount; i++)
3736 	{
3737 		if (us_teclayer_letters[i] == 0) xprintf(f, x_("\tx_(\"\")")); else
3738 			xprintf(f, x_("\tx_(\"%s\")"), us_teclayer_letters[i]);
3739 		if (i != tech->layercount-1) xprintf(f, x_(","));
3740 		xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3741 	}
3742 	xprintf(f, x_("};\n"));
3743 
3744 	/* write the SPICE information */
3745 	if ((us_tecflags&HASSPIRES) != 0)
3746 	{
3747 		xprintf(f, x_("static float %s_sim_spice_resistance[MAXLAYERS] = {\n"),
3748 			us_tecedmakesymbol(techname));
3749 		for(i=0; i<tech->layercount; i++)
3750 		{
3751 			xprintf(f, x_("\t%s"), us_tecedmakefloatstring(us_tecspice_res[i]));
3752 			if (i != tech->layercount-1) xprintf(f, x_(","));
3753 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3754 		}
3755 		xprintf(f, x_("};\n"));
3756 	}
3757 	if ((us_tecflags&HASSPICAP) != 0)
3758 	{
3759 		xprintf(f, x_("static float %s_sim_spice_capacitance[MAXLAYERS] = {\n"),
3760 			us_tecedmakesymbol(techname));
3761 		for(i=0; i<tech->layercount; i++)
3762 		{
3763 			xprintf(f, x_("\t%s"), us_tecedmakefloatstring(us_tecspice_cap[i]));
3764 			if (i != tech->layercount-1) xprintf(f, x_(","));
3765 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3766 		}
3767 		xprintf(f, x_("};\n"));
3768 	}
3769 	if ((us_tecflags&HASSPIECAP) != 0)
3770 	{
3771 		xprintf(f, x_("static float %s_sim_spice_edge_cap[MAXLAYERS] = {\n"),
3772 			us_tecedmakesymbol(techname));
3773 		for(i=0; i<tech->layercount; i++)
3774 		{
3775 			xprintf(f, x_("\t%s"), us_tecedmakefloatstring(us_tecspice_ecap[i]));
3776 			if (i != tech->layercount-1) xprintf(f, x_(","));
3777 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3778 		}
3779 		xprintf(f, x_("};\n"));
3780 	}
3781 
3782 	/* write the 3D information */
3783 	if ((us_tecflags&HAS3DINFO) != 0)
3784 	{
3785 		xprintf(f, x_("static INTBIG %s_3dheight_layers[MAXLAYERS] = {\n"),
3786 			us_tecedmakesymbol(techname));
3787 		for(i=0; i<tech->layercount; i++)
3788 		{
3789 			xprintf(f, x_("\t%ld"), us_tec3d_height[i]);
3790 			if (i != tech->layercount-1) xprintf(f, x_(","));
3791 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3792 		}
3793 		xprintf(f, x_("};\n"));
3794 		xprintf(f, x_("static INTBIG %s_3dthick_layers[MAXLAYERS] = {\n"),
3795 			us_tecedmakesymbol(techname));
3796 		for(i=0; i<tech->layercount; i++)
3797 		{
3798 			xprintf(f, x_("\t%ld"), us_tec3d_thickness[i]);
3799 			if (i != tech->layercount-1) xprintf(f, x_(","));
3800 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3801 		}
3802 		xprintf(f, x_("};\n"));
3803 	}
3804 	if ((us_tecflags&HASPRINTCOL) != 0)
3805 	{
3806 		xprintf(f, x_("static INTBIG %s_printcolors_layers[MAXLAYERS*5] = {\n"),
3807 			us_tecedmakesymbol(techname));
3808 		for(i=0; i<tech->layercount; i++)
3809 		{
3810 			xprintf(f, x_("\t%ld,%ld,%ld, %ld,%ld"), us_tecprint_colors[i*5],
3811 				us_tecprint_colors[i*5+1], us_tecprint_colors[i*5+2],
3812 					us_tecprint_colors[i*5+3], us_tecprint_colors[i*5+4]);
3813 			if (i != tech->layercount-1) xprintf(f, x_(","));
3814 			xprintf(f, x_("\t\t/* %s */\n"), us_teclayer_names[i]);
3815 		}
3816 		xprintf(f, x_("};\n"));
3817 	}
3818 
3819 	/* write the color map */
3820 	if ((us_tecflags&HASCOLORMAP) != 0)
3821 	{
3822 		/* determine the five transparent layers */
3823 		l1 = l2 = l3 = l4 = l5 = 0;
3824 		for(i=0; i<tech->layercount; i++)
3825 		{
3826 			if (tech->layers[i]->bits == LAYERT1 && l1 == 0)
3827 				l1 = us_teclayer_names[i]; else
3828 			if (tech->layers[i]->bits == LAYERT2 && l2 == 0)
3829 				l2 = us_teclayer_names[i]; else
3830 			if (tech->layers[i]->bits == LAYERT3 && l3 == 0)
3831 				l3 = us_teclayer_names[i]; else
3832 			if (tech->layers[i]->bits == LAYERT4 && l4 == 0)
3833 				l4 = us_teclayer_names[i]; else
3834 			if (tech->layers[i]->bits == LAYERT5 && l5 == 0)
3835 				l5 = us_teclayer_names[i];
3836 		}
3837 		if (l1 == 0) l1 = x_("layer 1");
3838 		if (l2 == 0) l2 = x_("layer 2");
3839 		if (l3 == 0) l3 = x_("layer 3");
3840 		if (l4 == 0) l4 = x_("layer 4");
3841 		if (l5 == 0) l5 = x_("layer 5");
3842 		xprintf(f, x_("\nstatic TECH_COLORMAP %s_colmap[32] =\n{\n"), us_tecedmakesymbol(techname));
3843 		for(i=0; i<32; i++)
3844 		{
3845 			xprintf(f, x_("\t{%3d,%3d,%3d}, /* %2d: "), us_teccolmap[i].red,
3846 				us_teccolmap[i].green, us_teccolmap[i].blue, i);
3847 			if ((i&1) != 0) xprintf(f, x_("%s"), l1); else
3848 				for(j=0; j<(INTBIG)estrlen(l1); j++) xprintf(f, x_(" "));
3849 			xprintf(f, x_("+"));
3850 			if ((i&2) != 0) xprintf(f, x_("%s"), l2); else
3851 				for(j=0; j<(INTBIG)estrlen(l2); j++) xprintf(f, x_(" "));
3852 			xprintf(f, x_("+"));
3853 			if ((i&4) != 0) xprintf(f, x_("%s"), l3); else
3854 				for(j=0; j<(INTBIG)estrlen(l3); j++) xprintf(f, x_(" "));
3855 			xprintf(f, x_("+"));
3856 			if ((i&8) != 0) xprintf(f, x_("%s"), l4); else
3857 				for(j=0; j<(INTBIG)estrlen(l4); j++) xprintf(f, x_(" "));
3858 			xprintf(f, x_("+"));
3859 			if ((i&16) != 0) xprintf(f, x_("%s"), l5); else
3860 				for(j=0; j<(INTBIG)estrlen(l5); j++) xprintf(f, x_(" "));
3861 			xprintf(f, x_(" */\n"));
3862 		}
3863 		xprintf(f, x_("};\n"));
3864 	}
3865 
3866 	/* write design rules */
3867 	if ((us_tecflags&(HASDRCMINWID|HASCONDRC|HASUNCONDRC|HASCONDRCW|HASUNCONDRCW|HASCONDRCM|HASUNCONDRCM|HASEDGEDRC)) != 0)
3868 	{
3869 		xprintf(f, x_("\n/******************** DESIGN RULES ********************/\n"));
3870 
3871 		/* write the DRC minimum width information */
3872 		if ((us_tecflags&HASDRCMINWID) != 0)
3873 		{
3874 			xprintf(f, x_("static INTBIG %s_minimum_width[MAXLAYERS] = {"),
3875 				us_tecedmakesymbol(techname));
3876 			for(i=0; i<tech->layercount; i++)
3877 			{
3878 				if (i != 0) xprintf(f, x_(", "));
3879 				xprintf(f, x_("%s"), us_tecedmakefract(us_tecdrc_rules->minwidth[i]));
3880 			}
3881 			xprintf(f, x_("};\n"));
3882 			if ((us_tecflags&HASDRCMINWIDR) != 0)
3883 			{
3884 				xprintf(f, x_("static char *%s_minimum_width_rule[MAXLAYERS] = {"),
3885 					us_tecedmakesymbol(techname));
3886 				for(i=0; i<tech->layercount; i++)
3887 				{
3888 					if (i != 0) xprintf(f, x_(", "));
3889 					xprintf(f, x_("x_(\"%s\")"), us_tecdrc_rules->minwidthR[i]);
3890 				}
3891 				xprintf(f, x_("};\n"));
3892 			}
3893 		}
3894 
3895 		if ((us_tecflags&HASCONDRC) != 0)
3896 		{
3897 			xprintf(f, x_("\nstatic INTBIG %s_connectedtable[] = {\n"),
3898 				us_tecedmakesymbol(techname));
3899 			us_teceditdumpdrctab(f, us_tecdrc_rules->conlist, tech, FALSE);
3900 			if ((us_tecflags&HASCONDRCR) != 0)
3901 			{
3902 				xprintf(f, x_("\nstatic char *%s_connectedtable_rule[] = {\n"),
3903 					us_tecedmakesymbol(techname));
3904 				us_teceditdumpdrctab(f, us_tecdrc_rules->conlistR, tech, TRUE);
3905 			}
3906 		}
3907 		if ((us_tecflags&HASUNCONDRC) != 0)
3908 		{
3909 			xprintf(f, x_("\nstatic INTBIG %s_unconnectedtable[] = {\n"),
3910 				us_tecedmakesymbol(techname));
3911 			us_teceditdumpdrctab(f, us_tecdrc_rules->unconlist, tech, FALSE);
3912 			if ((us_tecflags&HASUNCONDRCR) != 0)
3913 			{
3914 				xprintf(f, x_("\nstatic char *%s_unconnectedtable_rule[] = {\n"),
3915 					us_tecedmakesymbol(techname));
3916 				us_teceditdumpdrctab(f, us_tecdrc_rules->unconlistR, tech, TRUE);
3917 			}
3918 		}
3919 		if ((us_tecflags&HASCONDRCW) != 0)
3920 		{
3921 			xprintf(f, x_("\nstatic INTBIG %s_connectedtable_wide[] = {\n"),
3922 				us_tecedmakesymbol(techname));
3923 			us_teceditdumpdrctab(f, us_tecdrc_rules->conlistW, tech, FALSE);
3924 			if ((us_tecflags&HASCONDRCWR) != 0)
3925 			{
3926 				xprintf(f, x_("\nstatic char *%s_connectedtable_wide_rule[] = {\n"),
3927 					us_tecedmakesymbol(techname));
3928 				us_teceditdumpdrctab(f, us_tecdrc_rules->conlistWR, tech, TRUE);
3929 			}
3930 		}
3931 		if ((us_tecflags&HASUNCONDRCW) != 0)
3932 		{
3933 			xprintf(f, x_("\nstatic INTBIG %s_unconnectedtable_wide[] = {\n"),
3934 				us_tecedmakesymbol(techname));
3935 			us_teceditdumpdrctab(f, us_tecdrc_rules->unconlistW, tech, FALSE);
3936 			if ((us_tecflags&HASUNCONDRCWR) != 0)
3937 			{
3938 				xprintf(f, x_("\nstatic char *%s_unconnectedtable_wide_rule[] = {\n"),
3939 					us_tecedmakesymbol(techname));
3940 				us_teceditdumpdrctab(f, us_tecdrc_rules->unconlistWR, tech, TRUE);
3941 			}
3942 		}
3943 		if ((us_tecflags&HASCONDRCM) != 0)
3944 		{
3945 			xprintf(f, x_("\nstatic INTBIG %s_connectedtable_multi[] = {\n"),
3946 				us_tecedmakesymbol(techname));
3947 			us_teceditdumpdrctab(f, us_tecdrc_rules->conlistM, tech, FALSE);
3948 			if ((us_tecflags&HASCONDRCMR) != 0)
3949 			{
3950 				xprintf(f, x_("\nstatic char *%s_connectedtable_multi_rule[] = {\n"),
3951 					us_tecedmakesymbol(techname));
3952 				us_teceditdumpdrctab(f, us_tecdrc_rules->conlistMR, tech, TRUE);
3953 			}
3954 		}
3955 		if ((us_tecflags&HASUNCONDRCM) != 0)
3956 		{
3957 			xprintf(f, x_("\nstatic INTBIG %s_unconnectedtable_multi[] = {\n"),
3958 				us_tecedmakesymbol(techname));
3959 			us_teceditdumpdrctab(f, us_tecdrc_rules->unconlistM, tech, FALSE);
3960 			if ((us_tecflags&HASUNCONDRCMR) != 0)
3961 			{
3962 				xprintf(f, x_("\nstatic char *%s_unconnectedtable_multi_rule[] = {\n"),
3963 					us_tecedmakesymbol(techname));
3964 				us_teceditdumpdrctab(f, us_tecdrc_rules->unconlistMR, tech, TRUE);
3965 			}
3966 		}
3967 		if ((us_tecflags&HASEDGEDRC) != 0)
3968 		{
3969 			xprintf(f, x_("\nstatic INTBIG %s_edgetable[] = {\n"),
3970 				us_tecedmakesymbol(techname));
3971 			us_teceditdumpdrctab(f, us_tecdrc_rules->edgelist, tech, FALSE);
3972 			if ((us_tecflags&HASEDGEDRCR) != 0)
3973 			{
3974 				xprintf(f, x_("\nstatic char *%s_edgetable_rule[] = {\n"),
3975 					us_tecedmakesymbol(techname));
3976 				us_teceditdumpdrctab(f, us_tecdrc_rules->edgelistR, tech, TRUE);
3977 			}
3978 		}
3979 	}
3980 }
3981 
us_teceditdumpdrctab(FILE * f,void * distances,TECHNOLOGY * tech,BOOLEAN isstring)3982 void us_teceditdumpdrctab(FILE *f, void *distances, TECHNOLOGY *tech, BOOLEAN isstring)
3983 {
3984 	REGISTER INTBIG i, j;
3985 	REGISTER INTBIG amt, mod, *amtlist;
3986 	CHAR shortname[7], *msg, **distlist;
3987 
3988 	for(i=0; i<6; i++)
3989 	{
3990 		xprintf(f, x_("/*            "));
3991 		for(j=0; j<tech->layercount; j++)
3992 		{
3993 			if ((INTBIG)estrlen(us_teclayer_iname[j]) <= i) xprintf(f, x_(" ")); else
3994 				xprintf(f, x_("%c"), us_teclayer_iname[j][i]);
3995 			xprintf(f, x_("  "));
3996 		}
3997 		xprintf(f, x_(" */\n"));
3998 	}
3999 	if (isstring) distlist = (CHAR **)distances; else
4000 		amtlist = (INTBIG *)distances;
4001 	for(j=0; j<tech->layercount; j++)
4002 	{
4003 		(void)estrncpy(shortname, us_teclayer_iname[j], 6);
4004 		shortname[6] = 0;
4005 		xprintf(f, x_("/* %-6s */ "), shortname);
4006 		for(i=0; i<j; i++) xprintf(f, x_("   "));
4007 		for(i=j; i<tech->layercount; i++)
4008 		{
4009 			if (isstring)
4010 			{
4011 				msg = *distlist++;
4012 				xprintf(f, x_("x_(\"%s\")"), msg);
4013 			} else
4014 			{
4015 				amt = *amtlist++;
4016 				if (amt < 0) xprintf(f, x_("XX")); else
4017 				{
4018 					mod = amt % WHOLE;
4019 					if (mod == 0) xprintf(f, x_("K%ld"), amt/WHOLE); else
4020 					if (mod == WHOLE/2) xprintf(f, x_("H%ld"), amt/WHOLE); else
4021 					if (mod == WHOLE/4) xprintf(f, x_("Q%ld"), amt/WHOLE); else
4022 					if (mod == WHOLE/4*3) xprintf(f, x_("T%ld"), amt/WHOLE); else
4023 						xprintf(f, x_("%ld"), amt);
4024 				}
4025 			}
4026 			if (j != tech->layercount-1 || i != tech->layercount-1)
4027 				xprintf(f, x_(","));
4028 		}
4029 		xprintf(f, x_("\n"));
4030 	}
4031 	xprintf(f, x_("};\n"));
4032 }
4033 
4034 /*
4035  * routine to dump the arc information in technology "tech" to the stream in
4036  * "f".
4037  */
us_teceditdumparcs(FILE * f,TECHNOLOGY * tech,CHAR * techname)4038 void us_teceditdumparcs(FILE *f, TECHNOLOGY *tech, CHAR *techname)
4039 {
4040 	REGISTER INTBIG i, j, k;
4041 
4042 	/* print the header */
4043 	xprintf(f, x_("\n/******************** ARCS ********************/\n"));
4044 
4045 	/* compute the width of the widest arc name */
4046 	k = 12;
4047 	for(i=0; i<tech->arcprotocount; i++)
4048 		k = maxi(k, estrlen(tech->arcprotos[i]->arcname));
4049 	k++;
4050 
4051 	/* write the number of arcs */
4052 	xprintf(f, x_("\n#define ARCPROTOCOUNT"));
4053 	for(j=12; j<k; j++) xprintf(f, x_(" "));
4054 	xprintf(f, x_("%ld\n"), tech->arcprotocount);
4055 
4056 	/* write defines for each arc */
4057 	for(i=0; i<tech->arcprotocount; i++)
4058 	{
4059 		xprintf(f, x_("#define A%s"), us_tecedmakeupper(tech->arcprotos[i]->arcname));
4060 		for(j=estrlen(tech->arcprotos[i]->arcname); j<k; j++)
4061 			xprintf(f, x_(" "));
4062 		xprintf(f, x_("%ld\t\t\t\t/* %s */\n"), i, tech->arcprotos[i]->arcname);
4063 	}
4064 
4065 	/* now write the arcs */
4066 	for(i=0; i<tech->arcprotocount; i++)
4067 	{
4068 		xprintf(f, x_("\nstatic TECH_ARCLAY %s_al_%ld[] = {"),
4069 			us_tecedmakesymbol(techname), i);
4070 		for(k=0; k<tech->arcprotos[i]->laycount; k++)
4071 		{
4072 			if (k != 0) xprintf(f, x_(", "));
4073 			xprintf(f, x_("{"));
4074 			xprintf(f, x_("L%s,"), us_teclayer_iname[tech->arcprotos[i]->list[k].lay]);
4075 			if (tech->arcprotos[i]->list[k].off == 0) xprintf(f, x_("0,")); else
4076 				xprintf(f, x_("%s,"), us_tecedmakefract(tech->arcprotos[i]->list[k].off));
4077 			if (tech->arcprotos[i]->list[k].style == FILLED) xprintf(f, x_("FILLED}")); else
4078 				xprintf(f, x_("CLOSED}"));
4079 		}
4080 		xprintf(f, x_("};\n"));
4081 		xprintf(f, x_("static TECH_ARCS %s_a_%ld = {\n"), us_tecedmakesymbol(techname), i);
4082 		xprintf(f, x_("\tx_(\"%s\"), "), tech->arcprotos[i]->arcname);
4083 		xprintf(f, x_("%s, "), us_tecedmakefract(tech->arcprotos[i]->arcwidth));
4084 		xprintf(f, x_("A%s,NOARCPROTO,\n"), us_tecedmakeupper(tech->arcprotos[i]->arcname));
4085 		xprintf(f, x_("\t%d, %s_al_%ld,\n"), tech->arcprotos[i]->laycount,
4086 			us_tecedmakesymbol(techname), i);
4087 		for(j=0; us_tecarc_functions[j].name != 0; j++)
4088 			if (us_tecarc_functions[j].value ==
4089 				(INTBIG)((tech->arcprotos[i]->initialbits&AFUNCTION)>>AFUNCTIONSH))
4090 		{
4091 			xprintf(f, x_("\t(%s<<AFUNCTIONSH)"), us_tecarc_functions[j].constant);
4092 			break;
4093 		}
4094 		if (us_tecarc_functions[j].name == 0)                    xprintf(f, x_("\t(APUNKNOWN<<AFUNCTIONSH)"));
4095 		if ((tech->arcprotos[i]->initialbits&WANTFIXANG) != 0)   xprintf(f, x_("|WANTFIXANG"));
4096 		if ((tech->arcprotos[i]->initialbits&CANWIPE) != 0)      xprintf(f, x_("|CANWIPE"));
4097 		if ((tech->arcprotos[i]->initialbits&WANTNOEXTEND) != 0) xprintf(f, x_("|WANTNOEXTEND"));
4098 		xprintf(f, x_("|(%ld<<AANGLEINCSH)"), (tech->arcprotos[i]->initialbits&AANGLEINC)>>AANGLEINCSH);
4099 		xprintf(f, x_("};\n"));
4100 	}
4101 
4102 	/* print the summary */
4103 	xprintf(f, x_("\nTECH_ARCS *%s_arcprotos[ARCPROTOCOUNT+1] = {\n\t"),
4104 		us_tecedmakesymbol(techname));
4105 	for(i=0; i<tech->arcprotocount; i++)
4106 		xprintf(f, x_("&%s_a_%ld, "), us_tecedmakesymbol(techname), i);
4107 	xprintf(f, x_("((TECH_ARCS *)-1)};\n"));
4108 
4109 	/* print the variable with the width offsets */
4110 	if ((us_tecflags&HASARCWID) != 0)
4111 	{
4112 		xprintf(f, x_("\nstatic INTBIG %s_arc_widoff[ARCPROTOCOUNT] = {"),
4113 			us_tecedmakesymbol(techname));
4114 		for(i=0; i<tech->arcprotocount; i++)
4115 		{
4116 			if (i != 0) xprintf(f, x_(", "));
4117 			if (us_tecarc_widoff[i] == 0) xprintf(f, x_("0")); else
4118 				xprintf(f, x_("%s"), us_tecedmakefract(us_tecarc_widoff[i]));
4119 		}
4120 		xprintf(f, x_("};\n"));
4121 	}
4122 }
4123 
4124 /*
4125  * routine to dump the node information in technology "tech" to the stream in
4126  * "f".
4127  */
us_teceditdumpnodes(FILE * f,TECHNOLOGY * tech,CHAR * techname)4128 void us_teceditdumpnodes(FILE *f, TECHNOLOGY *tech, CHAR *techname)
4129 {
4130 	REGISTER RULE *r;
4131 	REGISTER INTBIG i, j, k, l, tot;
4132 	CHAR *ab, *sym;
4133 	BOOLEAN yaxis;
4134 	REGISTER PCON *pc;
4135 	REGISTER TECH_POLYGON *plist;
4136 	REGISTER TECH_SERPENT *slist;
4137 	REGISTER TECH_NODES *nlist;
4138 	REGISTER void *infstr;
4139 
4140 	/* make abbreviations for each node */
4141 	for(i=0; i<tech->nodeprotocount; i++)
4142 	{
4143 		(void)allocstring(&ab, makeabbrev(tech->nodeprotos[i]->nodename, FALSE), el_tempcluster);
4144 		tech->nodeprotos[i]->creation = (NODEPROTO *)ab;
4145 
4146 		/* loop until the name is unique */
4147 		for(;;)
4148 		{
4149 			/* see if a previously assigned abbreviation is the same */
4150 			for(j=0; j<i; j++)
4151 				if (namesame(ab, (CHAR *)tech->nodeprotos[j]->creation) == 0) break;
4152 			if (j == i) break;
4153 
4154 			/* name conflicts: change it */
4155 			l = estrlen(ab);
4156 			if (ab[l-1] >= '0' && ab[l-1] <= '8') ab[l-1]++; else
4157 			{
4158 				infstr = initinfstr();
4159 				addstringtoinfstr(infstr, ab);
4160 				addtoinfstr(infstr, '0');
4161 				(void)reallocstring(&ab, returninfstr(infstr), el_tempcluster);
4162 				tech->nodeprotos[i]->creation = (NODEPROTO *)ab;
4163 			}
4164 		}
4165 	}
4166 
4167 	/* write the port lists */
4168 	xprintf(f, x_("\n/******************** PORT CONNECTIONS ********************/\n\n"));
4169 	i = 1;
4170 	for(pc = us_tecedfirstpcon; pc != NOPCON; pc = pc->nextpcon)
4171 	{
4172 		pc->pcindex = i++;
4173 		xprintf(f, x_("static INTBIG %s_pc_%ld[] = {-1, "),
4174 			us_tecedmakesymbol(techname), pc->pcindex);
4175 		for(j=0; j<pc->total; j++)
4176 		{
4177 			k = pc->connects[j+1];
4178 			xprintf(f, x_("A%s, "), us_tecedmakeupper(tech->arcprotos[k]->arcname));
4179 		}
4180 		xprintf(f, x_("ALLGEN, -1};\n"));
4181 	}
4182 
4183 	xprintf(f, x_("\n/******************** RECTANGLE DESCRIPTIONS ********************/"));
4184 	xprintf(f, x_("\n\n"));
4185 
4186 	/* print box information */
4187 	i = 1;
4188 	for(r = us_tecedfirstrule; r != NORULE; r = r->nextrule)
4189 	{
4190 		if (!r->used) continue;
4191 		r->rindex = i++;
4192 		xprintf(f, x_("static INTBIG %s_box%ld[%ld] = {"),
4193 			us_tecedmakesymbol(techname), r->rindex, r->count);
4194 		for(j=0; j<r->count; j += 2)
4195 		{
4196 			if (j != 0) xprintf(f, x_(", "));
4197 			if ((j%4) == 0) yaxis = FALSE; else yaxis = TRUE;
4198 			xprintf(f, x_("%s"), us_tecededgelabel(r->value[j], r->value[j+1], yaxis));
4199 		}
4200 		if (r->istext != 0)
4201 			xprintf(f, x_(", x_(\"%s\")"), (CHAR *)r->value[r->count]);
4202 		xprintf(f, x_("};\n"));
4203 	}
4204 
4205 	xprintf(f, x_("\n/******************** NODES ********************/\n"));
4206 
4207 	/* compute widest node name */
4208 	k = 13;
4209 	for(i=0; i<tech->nodeprotocount; i++)
4210 		k = maxi(k, estrlen((CHAR *)tech->nodeprotos[i]->creation));
4211 	k++;
4212 
4213 	/* write the total define */
4214 	xprintf(f, x_("\n#define NODEPROTOCOUNT"));
4215 	for(j=13; j<k; j++) xprintf(f, x_(" "));
4216 	xprintf(f, x_("%ld\n"), tech->nodeprotocount);
4217 
4218 	/* write the other defines */
4219 	for(i=0; i<tech->nodeprotocount; i++)
4220 	{
4221 		ab = (CHAR *)tech->nodeprotos[i]->creation;
4222 		xprintf(f, x_("#define N%s"), us_tecedmakeupper(ab));
4223 		for(j=estrlen(ab); j<k; j++) xprintf(f, x_(" "));
4224 		xprintf(f, x_("%ld\t\t\t\t/* %s */\n"), i+1, tech->nodeprotos[i]->nodename);
4225 	}
4226 
4227 	/* print node information */
4228 	for(i=0; i<tech->nodeprotocount; i++)
4229 	{
4230 		/* header comment */
4231 		nlist = tech->nodeprotos[i];
4232 		ab = (CHAR *)nlist->creation;
4233 		xprintf(f, x_("\n/* %s */\n"), nlist->nodename);
4234 
4235 		/* print ports */
4236 		xprintf(f, x_("static TECH_PORTS %s_%s_p[] = {\n"), us_tecedmakesymbol(techname), ab);
4237 		for(j=0; j<nlist->portcount; j++)
4238 		{
4239 			if (j != 0) xprintf(f, x_(",\n"));
4240 
4241 			/* the name of the connection structure */
4242 			for(pc = us_tecedfirstpcon; pc != NOPCON; pc = pc->nextpcon)
4243 				if (pc->connects == nlist->portlist[j].portarcs) break;
4244 			if (pc != NOPCON)
4245 				xprintf(f, x_("\t{%s_pc_%ld, "), us_tecedmakesymbol(techname), pc->pcindex);
4246 
4247 			/* the port name */
4248 			xprintf(f, x_("x_(\"%s\"), NOPORTPROTO, "), nlist->portlist[j].protoname);
4249 
4250 			/* the port userbits */
4251 			xprintf(f, x_("(%ld<<PORTARANGESH)"),
4252 				(nlist->portlist[j].initialbits&PORTARANGE)>>PORTARANGESH);
4253 			if ((nlist->portlist[j].initialbits&PORTANGLE) != 0)
4254 				xprintf(f, x_("|(%ld<<PORTANGLESH)"),
4255 					(nlist->portlist[j].initialbits&PORTANGLE)>>PORTANGLESH);
4256 			if ((nlist->portlist[j].initialbits&PORTNET) != 0)
4257 				xprintf(f, x_("|(%ld<<PORTNETSH)"), (nlist->portlist[j].initialbits&PORTNET)>>PORTNETSH);
4258 			xprintf(f, x_(",\n"));
4259 
4260 			/* the port area */
4261 			xprintf(f, x_("\t\t%s, %s, %s, %s}"),
4262 				us_tecededgelabel(nlist->portlist[j].lowxmul, nlist->portlist[j].lowxsum, FALSE),
4263 				us_tecededgelabel(nlist->portlist[j].lowymul, nlist->portlist[j].lowysum, TRUE),
4264 				us_tecededgelabel(nlist->portlist[j].highxmul, nlist->portlist[j].highxsum, FALSE),
4265 				us_tecededgelabel(nlist->portlist[j].highymul, nlist->portlist[j].highysum, TRUE));
4266 		}
4267 		xprintf(f, x_("};\n"));
4268 
4269 		/* print layers */
4270 		for(k=0; k<2; k++)
4271 		{
4272 			if (nlist->special == SERPTRANS)
4273 			{
4274 				if (k == 0)
4275 				{
4276 					xprintf(f, x_("static TECH_SERPENT %s_%s_l[] = {\n"),
4277 						us_tecedmakesymbol(techname), ab);
4278 					tot = nlist->layercount;
4279 				} else
4280 				{
4281 					xprintf(f, x_("static TECH_SERPENT %s_%sE_l[] = {\n"),
4282 						us_tecedmakesymbol(techname), ab);
4283 					tot = nlist->layercount + 1;
4284 				}
4285 			} else
4286 			{
4287 				if (k != 0) continue;
4288 				xprintf(f, x_("static TECH_POLYGON %s_%s_l[] = {\n"),
4289 					us_tecedmakesymbol(techname), ab);
4290 				tot = nlist->layercount;
4291 			}
4292 			for(j=0; j<tot; j++)
4293 			{
4294 				if (j != 0) xprintf(f, x_(",\n"));
4295 				xprintf(f, x_("\t"));
4296 				if (nlist->special == SERPTRANS)
4297 				{
4298 					xprintf(f, x_("{"));
4299 					if (k == 0) plist = &nlist->gra[j].basics;
4300 						else plist = &nlist->ele[j].basics;
4301 				} else plist = &nlist->layerlist[j];
4302 				xprintf(f, x_("{L%s,"), us_teclayer_iname[plist->layernum]);
4303 				xprintf(f, x_(" %d,"), plist->portnum);
4304 				xprintf(f, x_(" %d,"), plist->count);
4305 				switch (plist->style)
4306 				{
4307 					case FILLEDRECT:     xprintf(f, x_(" FILLEDRECT,"));     break;
4308 					case CLOSEDRECT:     xprintf(f, x_(" CLOSEDRECT,"));     break;
4309 					case CROSSED:        xprintf(f, x_(" CROSSED,"));        break;
4310 					case FILLED:         xprintf(f, x_(" FILLED,"));         break;
4311 					case CLOSED:         xprintf(f, x_(" CLOSED,"));         break;
4312 					case OPENED:         xprintf(f, x_(" OPENED,"));         break;
4313 					case OPENEDT1:       xprintf(f, x_(" OPENEDT1,"));       break;
4314 					case OPENEDT2:       xprintf(f, x_(" OPENEDT2,"));       break;
4315 					case OPENEDT3:       xprintf(f, x_(" OPENEDT3,"));       break;
4316 					case VECTORS:        xprintf(f, x_(" VECTORS,"));        break;
4317 					case CIRCLE:         xprintf(f, x_(" CIRCLE,"));         break;
4318 					case THICKCIRCLE:    xprintf(f, x_(" THICKCIRCLE,"));    break;
4319 					case DISC:           xprintf(f, x_(" DISC,"));           break;
4320 					case CIRCLEARC:      xprintf(f, x_(" CIRCLEARC,"));      break;
4321 					case THICKCIRCLEARC: xprintf(f, x_(" THICKCIRCLEARC,")); break;
4322 					case TEXTCENT:       xprintf(f, x_(" TEXTCENT,"));       break;
4323 					case TEXTTOP:        xprintf(f, x_(" TEXTTOP,"));        break;
4324 					case TEXTBOT:        xprintf(f, x_(" TEXTBOT,"));        break;
4325 					case TEXTLEFT:       xprintf(f, x_(" TEXTLEFT,"));       break;
4326 					case TEXTRIGHT:      xprintf(f, x_(" TEXTRIGHT,"));      break;
4327 					case TEXTTOPLEFT:    xprintf(f, x_(" TEXTTOPLEFT,"));    break;
4328 					case TEXTBOTLEFT:    xprintf(f, x_(" TEXTBOTLEFT,"));    break;
4329 					case TEXTTOPRIGHT:   xprintf(f, x_(" TEXTTOPRIGHT,"));   break;
4330 					case TEXTBOTRIGHT:   xprintf(f, x_(" TEXTBOTRIGHT,"));   break;
4331 					case TEXTBOX:        xprintf(f, x_(" TEXTBOX,"));        break;
4332 					default:             xprintf(f, x_(" ????,"));           break;
4333 				}
4334 				switch (plist->representation)
4335 				{
4336 					case BOX:    xprintf(f, x_(" BOX,"));     break;
4337 					case MINBOX: xprintf(f, x_(" MINBOX,"));  break;
4338 					case POINTS: xprintf(f, x_(" POINTS,"));  break;
4339 					default:     xprintf(f, x_(" ????,"));    break;
4340 				}
4341 				for(r = us_tecedfirstrule; r != NORULE; r = r->nextrule)
4342 					if (r->value == plist->points) break;
4343 				if (r != NORULE)
4344 					xprintf(f, x_(" %s_box%ld"), us_tecedmakesymbol(techname), r->rindex); else
4345 						xprintf(f, x_(" %s_box??"), us_tecedmakesymbol(techname));
4346 				xprintf(f, x_("}"));
4347 				if (nlist->special == SERPTRANS)
4348 				{
4349 					if (k == 0) slist = &nlist->gra[j]; else
4350 						slist = &nlist->ele[j];
4351 					xprintf(f, x_(", %s"), us_tecedmakefract(slist->lwidth));
4352 					xprintf(f, x_(", %s"), us_tecedmakefract(slist->rwidth));
4353 					xprintf(f, x_(", %s"), us_tecedmakefract(slist->extendt));
4354 					xprintf(f, x_(", %s}"), us_tecedmakefract(slist->extendb));
4355 				}
4356 			}
4357 			xprintf(f, x_("};\n"));
4358 		}
4359 
4360 		/* print the node information */
4361 		xprintf(f, x_("static TECH_NODES %s_%s = {\n"), us_tecedmakesymbol(techname), ab);
4362 		xprintf(f, x_("\tx_(\"%s\"), N%s, NONODEPROTO,\n"), nlist->nodename, us_tecedmakeupper(ab));
4363 		xprintf(f, x_("\t%s,"), us_tecedmakefract(nlist->xsize));
4364 		xprintf(f, x_(" %s,\n"), us_tecedmakefract(nlist->ysize));
4365 		xprintf(f, x_("\t%d, %s_%s_p,\n"), nlist->portcount, us_tecedmakesymbol(techname), ab);
4366 		if (nlist->special == SERPTRANS)
4367 			xprintf(f, x_("\t%d, (TECH_POLYGON *)0,\n"), nlist->layercount); else
4368 				xprintf(f, x_("\t%d, %s_%s_l,\n"), nlist->layercount,
4369 					us_tecedmakesymbol(techname), ab);
4370 		j = (nlist->initialbits&NFUNCTION)>>NFUNCTIONSH;
4371 		if (j < 0 || j >= MAXNODEFUNCTION) j = 0;
4372 		xprintf(f, x_("\t(%s<<NFUNCTIONSH)"), nodefunctionconstantname(j));
4373 		if ((nlist->initialbits&WIPEON1OR2) != 0) xprintf(f, x_("|WIPEON1OR2"));
4374 		if ((nlist->initialbits&HOLDSTRACE) != 0) xprintf(f, x_("|HOLDSTRACE"));
4375 		if ((nlist->initialbits&NSQUARE) != 0)    xprintf(f, x_("|NSQUARE"));
4376 		if ((nlist->initialbits&ARCSWIPE) != 0)   xprintf(f, x_("|ARCSWIPE"));
4377 		if ((nlist->initialbits&ARCSHRINK) != 0)  xprintf(f, x_("|ARCSHRINK"));
4378 		if ((nlist->initialbits&NODESHRINK) != 0) xprintf(f, x_("|NODESHRINK"));
4379 		if ((nlist->initialbits&LOCKEDPRIM) != 0) xprintf(f, x_("|LOCKEDPRIM"));
4380 		xprintf(f, x_(",\n"));
4381 		switch (nlist->special)
4382 		{
4383 			case 0:
4384 				xprintf(f, x_("\t0,0,0,0,0,0,0,0,0"));
4385 				break;
4386 			case SERPTRANS:
4387 				xprintf(f, x_("\tSERPTRANS,%d,"), nlist->f1);
4388 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f2));
4389 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f3));
4390 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f4));
4391 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f5));
4392 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f6));
4393 				xprintf(f, x_("%s_%s_l,"), us_tecedmakesymbol(techname), ab);
4394 				xprintf(f, x_("%s_%sE_l"), us_tecedmakesymbol(techname), ab);
4395 				break;
4396 			case MULTICUT:
4397 				xprintf(f, x_("\tMULTICUT,%s,"), us_tecedmakefract(nlist->f1));
4398 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f2));
4399 				xprintf(f, x_("%s,"), us_tecedmakefract(nlist->f3));
4400 				xprintf(f, x_("%s,0,0,0,0"), us_tecedmakefract(nlist->f4));
4401 				break;
4402 			case POLYGONAL:
4403 				xprintf(f, x_("\tPOLYGONAL,0,0,0,0,0,0,0,0"));
4404 				break;
4405 		}
4406 		xprintf(f, x_("};\n"));
4407 	}
4408 
4409 	/* print summary of nodes */
4410 	xprintf(f, x_("\nTECH_NODES *%s_nodeprotos[NODEPROTOCOUNT+1] = {\n\t"),
4411 		us_tecedmakesymbol(techname));
4412 	l = 4;
4413 	for(i=0; i<tech->nodeprotocount; i++)
4414 	{
4415 		sym = us_tecedmakesymbol(techname);
4416 		if (l + estrlen(sym) + estrlen((CHAR *)tech->nodeprotos[i]->creation) + 4 > 80)
4417 		{
4418 			xprintf(f, x_("\n\t"));
4419 			l = 4;
4420 		}
4421 		xprintf(f, x_("&%s_%s, "), sym, (CHAR *)tech->nodeprotos[i]->creation);
4422 		l += estrlen(sym) + estrlen((CHAR *)tech->nodeprotos[i]->creation) + 4;
4423 	}
4424 	xprintf(f, x_("((TECH_NODES *)-1)};\n"));
4425 
4426 	/* print highlight offset information */
4427 	xprintf(f, x_("\nstatic INTBIG %s_node_widoff[NODEPROTOCOUNT*4] = {\n\t"),
4428 		us_tecedmakesymbol(techname));
4429 	l = 4;
4430 	for(i=0; i<tech->nodeprotocount; i++)
4431 	{
4432 		if (i != 0) { xprintf(f, x_(", ")); l += 2; }
4433 		infstr = initinfstr();
4434 		if (us_tecnode_widoff[i*4] == 0) addtoinfstr(infstr, '0'); else
4435 			addstringtoinfstr(infstr, us_tecedmakefract(us_tecnode_widoff[i*4]));
4436 		addtoinfstr(infstr, ',');
4437 		if (us_tecnode_widoff[i*4+1] == 0) addtoinfstr(infstr, '0'); else
4438 			addstringtoinfstr(infstr, us_tecedmakefract(us_tecnode_widoff[i*4+1]));
4439 		addtoinfstr(infstr, ',');
4440 		if (us_tecnode_widoff[i*4+2] == 0) addtoinfstr(infstr, '0'); else
4441 			addstringtoinfstr(infstr, us_tecedmakefract(us_tecnode_widoff[i*4+2]));
4442 		addtoinfstr(infstr, ',');
4443 		if (us_tecnode_widoff[i*4+3] == 0) addtoinfstr(infstr, '0'); else
4444 			addstringtoinfstr(infstr, us_tecedmakefract(us_tecnode_widoff[i*4+3]));
4445 		sym = returninfstr(infstr);
4446 		l += estrlen(sym);
4447 		if (l > 80)
4448 		{
4449 			xprintf(f, x_("\n\t"));
4450 			l = 4;
4451 		}
4452 		xprintf(f, x_("%s"), sym);
4453 	}
4454 	xprintf(f, x_("};\n"));
4455 
4456 	/* print grab point informaton if it exists */
4457 	if ((us_tecflags&HASGRAB) != 0 && us_tecnode_grabcount > 0)
4458 	{
4459 		xprintf(f, x_("\nstatic INTBIG %s_centergrab[] = {\n"), us_tecedmakesymbol(techname));
4460 		for(i=0; i<us_tecnode_grabcount; i += 3)
4461 		{
4462 			ab = (CHAR *)tech->nodeprotos[us_tecnode_grab[i]-1]->creation;
4463 			xprintf(f, x_("\tN%s, %ld, %ld"), us_tecedmakeupper(ab), us_tecnode_grab[i+1],
4464 				us_tecnode_grab[i+2]);
4465 			if (i != us_tecnode_grabcount-3) xprintf(f, x_(",\n"));
4466 		}
4467 		xprintf(f, x_("\n};\n"));
4468 	}
4469 
4470 	/* print minimum node size informaton if it exists */
4471 	if ((us_tecflags&HASMINNODE) != 0)
4472 	{
4473 		xprintf(f, x_("\nstatic INTBIG %s_node_minsize[NODEPROTOCOUNT*2] = {\n"), us_tecedmakesymbol(techname));
4474 		for(i=0; i<tech->nodeprotocount; i++)
4475 		{
4476 			if (us_tecdrc_rules->minnodesize[i*2] < 0) ab = x_("XX"); else
4477 				ab = us_tecedmakefract(us_tecdrc_rules->minnodesize[i*2]);
4478 			xprintf(f, x_("\t%s, "), ab);
4479 			if (us_tecdrc_rules->minnodesize[i*2+1] < 0) ab = x_("XX"); else
4480 				ab = us_tecedmakefract(us_tecdrc_rules->minnodesize[i*2+1]);
4481 			xprintf(f, x_("%s"), ab);
4482 			if (i == tech->nodeprotocount-1) ab = x_(""); else ab = x_(",");
4483 			xprintf(f, x_("%s\t\t/* %s */\n"), ab, tech->nodeprotos[i]->nodename);
4484 		}
4485 		xprintf(f, x_("};\n"));
4486 	}
4487 	if ((us_tecflags&HASMINNODER) != 0)
4488 	{
4489 		xprintf(f, x_("\nstatic char *%s_node_minsize_rule[NODEPROTOCOUNT] = {\n"), us_tecedmakesymbol(techname));
4490 		for(i=0; i<tech->nodeprotocount; i++)
4491 		{
4492 			if (i == tech->nodeprotocount-1) ab = x_(""); else ab = x_(",");
4493 			xprintf(f, x_("\tx_(\"%s\")%s\t\t/* %s */\n"), us_tecdrc_rules->minnodesizeR[i], ab,
4494 				tech->nodeprotos[i]->nodename);
4495 		}
4496 		xprintf(f, x_("};\n"));
4497 	}
4498 
4499 	/* clean up */
4500 	for(i=0; i<tech->nodeprotocount; i++)
4501 	{
4502 		efree((CHAR *)tech->nodeprotos[i]->creation);
4503 		tech->nodeprotos[i]->creation = NONODEPROTO;
4504 	}
4505 }
4506 
4507 /*
4508  * routine to dump the variable information in technology "tech" to the stream in
4509  * "f".
4510  */
us_teceditdumpvars(FILE * f,TECHNOLOGY * tech,CHAR * techname)4511 void us_teceditdumpvars(FILE *f, TECHNOLOGY *tech, CHAR *techname)
4512 {
4513 	REGISTER INTBIG i, j, k;
4514 	REGISTER CHAR *pt;
4515 	REGISTER VARIABLE *var;
4516 
4517 	xprintf(f, x_("\n/******************** VARIABLE AGGREGATION ********************/\n"));
4518 
4519 	/* write any miscellaneous string array variables */
4520 	for(i=0; us_knownvars[i].varname != 0; i++)
4521 	{
4522 		var = getval((INTBIG)tech, VTECHNOLOGY, -1, us_knownvars[i].varname);
4523 		if (var == NOVARIABLE) continue;
4524 		if ((var->type&(VTYPE|VISARRAY)) == (VSTRING|VISARRAY))
4525 		{
4526 			xprintf(f, x_("\nchar *%s_%s[] = {\n"), us_tecedmakesymbol(techname),
4527 				us_knownvars[i].varname);
4528 			j = getlength(var);
4529 			for(k=0; k<j; k++)
4530 			{
4531 				xprintf(f, x_("\tx_(\""));
4532 				for(pt = ((CHAR **)var->addr)[k]; *pt != 0; pt++)
4533 				{
4534 					if (*pt == '"') xprintf(f, x_("\\"));
4535 					xprintf(f, x_("%c"), *pt);
4536 				}
4537 				xprintf(f, x_("\"),\n"));
4538 			}
4539 			xprintf(f, x_("\tNOSTRING};\n"));
4540 		}
4541 	}
4542 
4543 	xprintf(f, x_("\nTECH_VARIABLES %s_variables[] =\n{\n"), us_tecedmakesymbol(techname));
4544 
4545 	xprintf(f, x_("\t{x_(\"TECH_layer_names\"), (CHAR *)%s_layer_names, 0.0,\n"),
4546 		us_tecedmakesymbol(techname));
4547 	xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4548 
4549 	xprintf(f, x_("\t{x_(\"TECH_layer_function\"), (CHAR *)%s_layer_function, 0.0,\n"),
4550 		us_tecedmakesymbol(techname));
4551 	xprintf(f, x_("\t\tVINTEGER|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4552 
4553 	xprintf(f, x_("\t{x_(\"TECH_node_width_offset\"), (CHAR *)%s_node_widoff, 0.0,\n"),
4554 		us_tecedmakesymbol(techname));
4555 	xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|((NODEPROTOCOUNT*4)<<VLENGTHSH)},\n"));
4556 	if ((us_tecflags&HASGRAB) != 0 && us_tecnode_grabcount > 0)
4557 		xprintf(f, x_("\t{x_(\"prototype_center\"), (CHAR *)%s_centergrab, 0.0, %ld},\n"),
4558 			us_tecedmakesymbol(techname), us_tecnode_grabcount/3);
4559 
4560 	if ((us_tecflags&HASMINNODE) != 0)
4561 	{
4562 		xprintf(f, x_("\t{x_(\"DRC_min_node_size\"), (CHAR *)%s_node_minsize, 0.0,\n"),
4563 			us_tecedmakesymbol(techname));
4564 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|((NODEPROTOCOUNT*2)<<VLENGTHSH)},\n"));
4565 	}
4566 	if ((us_tecflags&HASMINNODER) != 0)
4567 	{
4568 		xprintf(f, x_("\t{x_(\"DRC_min_node_size_rule\"), (CHAR *)%s_node_minsize_rule, 0.0,\n"),
4569 			us_tecedmakesymbol(techname));
4570 		xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(NODEPROTOCOUNT<<VLENGTHSH)},\n"));
4571 	}
4572 
4573 	if ((us_tecflags&HASARCWID) != 0)
4574 	{
4575 		xprintf(f, x_("\t{x_(\"TECH_arc_width_offset\"), (CHAR *)%s_arc_widoff, 0.0,\n"),
4576 			us_tecedmakesymbol(techname));
4577 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|(ARCPROTOCOUNT<<VLENGTHSH)},\n"));
4578 	}
4579 
4580 	if ((us_tecflags&HAS3DINFO) != 0)
4581 	{
4582 		xprintf(f, x_("\t{x_(\"TECH_layer_3dthickness\"), (CHAR *)%s_3dthick_layers, 0.0,\n"),
4583 			us_tecedmakesymbol(techname));
4584 		xprintf(f, x_("\t\tVINTEGER|VDONTSAVE|VISARRAY|(ARCPROTOCOUNT<<VLENGTHSH)},\n"));
4585 		xprintf(f, x_("\t{x_(\"TECH_layer_3dheight\"), (CHAR *)%s_3dheight_layers, 0.0,\n"),
4586 			us_tecedmakesymbol(techname));
4587 		xprintf(f, x_("\t\tVINTEGER|VDONTSAVE|VISARRAY|(ARCPROTOCOUNT<<VLENGTHSH)},\n"));
4588 	}
4589 	if ((us_tecflags&HASPRINTCOL) != 0)
4590 	{
4591 		xprintf(f, x_("\t{x_(\"USER_print_colors\"), (CHAR *)%s_printcolors_layers, 0.0,\n"),
4592 			us_tecedmakesymbol(techname));
4593 		xprintf(f, x_("\t\tVINTEGER|VDONTSAVE|VISARRAY|((MAXLAYERS*5)<<VLENGTHSH)},\n"));
4594 	}
4595 
4596 	xprintf(f, x_("\t{x_(\"USER_layer_letters\"), (CHAR *)%s_layer_letters, 0.0,\n"),
4597 		us_tecedmakesymbol(techname));
4598 	xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4599 
4600 	if ((us_tecflags&HASCOLORMAP) != 0)
4601 	{
4602 		xprintf(f, x_("\t{x_(\"USER_color_map\"), (CHAR *)%s_colmap, 0.0,\n"),
4603 			us_tecedmakesymbol(techname));
4604 		xprintf(f, x_("\t\tVCHAR|VDONTSAVE|VISARRAY|((sizeof %s_colmap)<<VLENGTHSH)},\n"),
4605 			us_tecedmakesymbol(techname));
4606 	}
4607 
4608 	if ((us_tecflags&HASCIF) != 0)
4609 	{
4610 		xprintf(f, x_("\t{x_(\"IO_cif_layer_names\"), (CHAR *)%s_cif_layers, 0.0,\n"),
4611 			us_tecedmakesymbol(techname));
4612 		xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4613 	}
4614 
4615 	if ((us_tecflags&HASDXF) != 0)
4616 	{
4617 		xprintf(f, x_("\t{x_(\"IO_dxf_layer_names\"), (CHAR *)%s_dxf_layers, 0.0,\n"),
4618 			us_tecedmakesymbol(techname));
4619 		xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4620 	}
4621 
4622 	if ((us_tecflags&HASGDS) != 0)
4623 	{
4624 		xprintf(f, x_("\t{x_(\"IO_gds_layer_numbers\"), (CHAR *)%s_gds_layers, 0.0,\n"),
4625 			us_tecedmakesymbol(techname));
4626 		xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4627 	}
4628 
4629 	if ((us_tecflags&HASDRCMINWID) != 0)
4630 	{
4631 		xprintf(f, x_("\t{x_(\"DRC_min_width\"), (CHAR *)%s_minimum_width, 0.0,\n"),
4632 			us_tecedmakesymbol(techname));
4633 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4634 		if ((us_tecflags&HASDRCMINWIDR) != 0)
4635 		{
4636 			xprintf(f, x_("\t{x_(\"DRC_min_width_rule\"), (CHAR *)%s_minimum_width_rule, 0.0,\n"),
4637 				us_tecedmakesymbol(techname));
4638 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4639 		}
4640 	}
4641 	if ((us_tecflags&(HASCONDRCW|HASUNCONDRCW)) != 0)
4642 	{
4643 		xprintf(f, x_("\t{x_(\"DRC_wide_limit\"), (CHAR *)%ld, 0.0,\n"),
4644 			us_tecdrc_rules->widelimit);
4645 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE},\n"));
4646 	}
4647 
4648 	if ((us_tecflags&HASCONDRC) != 0)
4649 	{
4650 		xprintf(f, x_("\t{x_(\"DRC_min_connected_distances\"), (CHAR *)%s_connectedtable, 0.0,\n"),
4651 			us_tecedmakesymbol(techname));
4652 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4653 		xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4654 			us_tecedmakesymbol(techname));
4655 		if ((us_tecflags&HASCONDRCR) != 0)
4656 		{
4657 			xprintf(f, x_("\t{x_(\"DRC_min_connected_distances_rule\"), (CHAR *)%s_connectedtable_rule, 0.0,\n"),
4658 				us_tecedmakesymbol(techname));
4659 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4660 			xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable_rule)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4661 				us_tecedmakesymbol(techname));
4662 		}
4663 	}
4664 	if ((us_tecflags&HASUNCONDRC) != 0)
4665 	{
4666 		xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances\"), (CHAR *)%s_unconnectedtable, 0.0,\n"),
4667 			us_tecedmakesymbol(techname));
4668 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4669 		xprintf(f, x_("\t\t   (((sizeof %s_unconnectedtable)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4670 			us_tecedmakesymbol(techname));
4671 		if ((us_tecflags&HASUNCONDRCR) != 0)
4672 		{
4673 			xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances_rule\"), (CHAR *)%s_unconnectedtable_rule, 0.0,\n"),
4674 				us_tecedmakesymbol(techname));
4675 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4676 			xprintf(f, x_("\t\t\t(((sizeof %s_unconnectedtable_rule)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4677 				us_tecedmakesymbol(techname));
4678 		}
4679 	}
4680 
4681 	if ((us_tecflags&HASCONDRCW) != 0)
4682 	{
4683 		xprintf(f, x_("\t{x_(\"DRC_min_connected_distances_wide\"), (CHAR *)%s_connectedtable_wide, 0.0,\n"),
4684 			us_tecedmakesymbol(techname));
4685 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4686 		xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable_wide)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4687 			us_tecedmakesymbol(techname));
4688 		if ((us_tecflags&HASCONDRCWR) != 0)
4689 		{
4690 			xprintf(f, x_("\t{x_(\"DRC_min_connected_distances_wide_rule\"), (CHAR *)%s_connectedtable_wide_rule, 0.0,\n"),
4691 				us_tecedmakesymbol(techname));
4692 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4693 			xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable_wide_rule)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4694 				us_tecedmakesymbol(techname));
4695 		}
4696 	}
4697 	if ((us_tecflags&HASUNCONDRCW) != 0)
4698 	{
4699 		xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances_wide\"), (CHAR *)%s_unconnectedtable_wide, 0.0,\n"),
4700 			us_tecedmakesymbol(techname));
4701 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4702 		xprintf(f, x_("\t\t   (((sizeof %s_unconnectedtable_wide)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4703 			us_tecedmakesymbol(techname));
4704 		if ((us_tecflags&HASUNCONDRCWR) != 0)
4705 		{
4706 			xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances_wide_rule\"), (CHAR *)%s_unconnectedtable_wide_rule, 0.0,\n"),
4707 				us_tecedmakesymbol(techname));
4708 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4709 			xprintf(f, x_("\t\t\t(((sizeof %s_unconnectedtable_wide)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4710 				us_tecedmakesymbol(techname));
4711 		}
4712 	}
4713 
4714 	if ((us_tecflags&HASCONDRCM) != 0)
4715 	{
4716 		xprintf(f, x_("\t{x_(\"DRC_min_connected_distances_multi\"), (CHAR *)%s_connectedtable_multi, 0.0,\n"),
4717 			us_tecedmakesymbol(techname));
4718 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4719 		xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable_multi)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4720 			us_tecedmakesymbol(techname));
4721 		if ((us_tecflags&HASCONDRCMR) != 0)
4722 		{
4723 			xprintf(f, x_("\t{x_(\"DRC_min_connected_distances_multi_rule\"), (CHAR *)%s_connectedtable_multi_rule, 0.0,\n"),
4724 				us_tecedmakesymbol(techname));
4725 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4726 			xprintf(f, x_("\t\t\t(((sizeof %s_connectedtable_multi_rule)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4727 				us_tecedmakesymbol(techname));
4728 		}
4729 	}
4730 	if ((us_tecflags&HASUNCONDRCM) != 0)
4731 	{
4732 		xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances_multi\"), (CHAR *)%s_unconnectedtable_multi, 0.0,\n"),
4733 			us_tecedmakesymbol(techname));
4734 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4735 		xprintf(f, x_("\t\t   (((sizeof %s_unconnectedtable_multi)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4736 			us_tecedmakesymbol(techname));
4737 		if ((us_tecflags&HASUNCONDRCMR) != 0)
4738 		{
4739 			xprintf(f, x_("\t{x_(\"DRC_min_unconnected_distances_multi_rule\"), (CHAR *)%s_unconnectedtable_multi_rule, 0.0,\n"),
4740 				us_tecedmakesymbol(techname));
4741 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4742 			xprintf(f, x_("\t\t\t(((sizeof %s_unconnectedtable_multi)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4743 				us_tecedmakesymbol(techname));
4744 		}
4745 	}
4746 	if ((us_tecflags&HASEDGEDRC) != 0)
4747 	{
4748 		xprintf(f, x_("\t{x_(\"DRC_min_edge_distances\"), (CHAR *)%s_edgetable, 0.0,\n"),
4749 			us_tecedmakesymbol(techname));
4750 		xprintf(f, x_("\t\tVFRACT|VDONTSAVE|VISARRAY|\n"));
4751 		xprintf(f, x_("\t\t   (((sizeof %s_edgetable)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4752 			us_tecedmakesymbol(techname));
4753 		if ((us_tecflags&HASEDGEDRCR) != 0)
4754 		{
4755 			xprintf(f, x_("\t{x_(\"DRC_min_edge_distances_rule\"), (CHAR *)%s_edgetable_rule, 0.0,\n"),
4756 				us_tecedmakesymbol(techname));
4757 			xprintf(f, x_("\t\tVSTRING|VDONTSAVE|VISARRAY|\n"));
4758 			xprintf(f, x_("\t\t\t(((sizeof %s_edgetable)/SIZEOFINTBIG)<<VLENGTHSH)},\n"),
4759 				us_tecedmakesymbol(techname));
4760 		}
4761 	}
4762 
4763 	if ((us_tecflags&HASSPIRES) != 0)
4764 	{
4765 		xprintf(f, x_("\t{x_(\"SIM_spice_resistance\"), (CHAR *)%s_sim_spice_resistance, 0.0,\n"),
4766 			us_tecedmakesymbol(techname));
4767 		xprintf(f, x_("\t\tVFLOAT|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4768 	}
4769 	if ((us_tecflags&HASSPICAP) != 0)
4770 	{
4771 		xprintf(f, x_("\t{x_(\"SIM_spice_capacitance\"), (CHAR *)%s_sim_spice_capacitance, 0.0,\n"),
4772 			us_tecedmakesymbol(techname));
4773 		xprintf(f, x_("\t\tVFLOAT|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4774 	}
4775 	if ((us_tecflags&HASSPIECAP) != 0)
4776 	{
4777 		xprintf(f, x_("\t{x_(\"SIM_spice_edge_capacitance\"), (CHAR *)%s_sim_spice_edge_cap, 0.0,\n"),
4778 			us_tecedmakesymbol(techname));
4779 		xprintf(f, x_("\t\tVFLOAT|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},\n"));
4780 	}
4781 
4782 	/* throw in pointers to any miscellaneous variables */
4783 	for(i=0; us_knownvars[i].varname != 0; i++)
4784 	{
4785 		var = getval((INTBIG)tech, VTECHNOLOGY, -1, us_knownvars[i].varname);
4786 		if (var == NOVARIABLE) continue;
4787 		xprintf(f, x_("\t{x_(\"%s\"), "), us_knownvars[i].varname);
4788 		switch (var->type&(VTYPE|VISARRAY))
4789 		{
4790 			case VINTEGER:
4791 				xprintf(f, x_("(CHAR *)%ld, 0.0, VINTEGER|VDONTSAVE"), var->addr);
4792 				break;
4793 			case VFLOAT:
4794 				xprintf(f, x_("(CHAR *)0, %g, VFLOAT|VDONTSAVE"), castfloat(var->addr));
4795 				break;
4796 			case VSTRING:
4797 				xprintf(f, x_("x_(\"%s\"), 0.0, VSTRING|VDONTSAVE"), (CHAR *)var->addr);
4798 				break;
4799 			case VSTRING|VISARRAY:
4800 				xprintf(f, x_("(CHAR *)%s_%s, 0.0,\n\t\tVSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)"),
4801 					us_tecedmakesymbol(techname), us_knownvars[i].varname);
4802 				break;
4803 		}
4804 		xprintf(f, x_("},\n"));
4805 	}
4806 
4807 	xprintf(f, x_("\t{NULL, NULL, 0.0, 0}\n};\n"));
4808 }
4809 
4810 /*
4811  * routine to convert the multiplication and addition factors in "mul" and
4812  * "add" into proper constant names.  The "yaxis" is false for X and 1 for Y
4813  */
us_tecededgelabel(INTBIG mul,INTBIG add,BOOLEAN yaxis)4814 CHAR *us_tecededgelabel(INTBIG mul, INTBIG add, BOOLEAN yaxis)
4815 {
4816 	CHAR line[20];
4817 	REGISTER INTBIG amt;
4818 	REGISTER void *infstr;
4819 
4820 	infstr = initinfstr();
4821 
4822 	/* handle constant distance from center (handles halves up to 5.5) */
4823 	if (mul == 0 && (add%H0) == 0 && abs(add) < K6)
4824 	{
4825 		addstringtoinfstr(infstr, x_("CENTER"));
4826 		if (add == 0) return(returninfstr(infstr));
4827 		if (!yaxis)
4828 		{
4829 			if (add < 0) addtoinfstr(infstr, 'L'); else addtoinfstr(infstr, 'R');
4830 		} else
4831 		{
4832 			if (add < 0) addtoinfstr(infstr, 'D'); else addtoinfstr(infstr, 'U');
4833 		}
4834 		amt = abs(add);
4835 		switch (amt%WHOLE)
4836 		{
4837 			case 0:  (void)esnprintf(line, 20, x_("%ld"),  amt/WHOLE);   break;
4838 			case H0: (void)esnprintf(line, 20, x_("%ldH"), amt/WHOLE);   break;
4839 		}
4840 		addstringtoinfstr(infstr, line);
4841 		return(returninfstr(infstr));
4842 	}
4843 
4844 	/* handle constant distance from edge (handles quarters up to 10, halves to 20) */
4845 	if ((mul == H0 || mul == -H0) &&
4846 		(((add%Q0) == 0 && abs(add) < K10) || ((add%H0) == 0 && abs(add) < K20)))
4847 	{
4848 		if (!yaxis)
4849 		{
4850 			if (mul < 0) addstringtoinfstr(infstr, x_("LEFT")); else
4851 				addstringtoinfstr(infstr, x_("RIGHT"));
4852 		} else
4853 		{
4854 			if (mul < 0) addstringtoinfstr(infstr, x_("BOT")); else
4855 				addstringtoinfstr(infstr, x_("TOP"));
4856 		}
4857 		if (add == 0) addstringtoinfstr(infstr, x_("EDGE")); else
4858 		{
4859 			amt = abs(add);
4860 			switch (amt%WHOLE)
4861 			{
4862 				case 0:  (void)esnprintf(line, 20, x_("IN%ld"),  amt/WHOLE);   break;
4863 				case Q0: (void)esnprintf(line, 20, x_("IN%ldQ"), amt/WHOLE);   break;
4864 				case H0: (void)esnprintf(line, 20, x_("IN%ldH"), amt/WHOLE);   break;
4865 				case T0: (void)esnprintf(line, 20, x_("IN%ldT"), amt/WHOLE);   break;
4866 			}
4867 			addstringtoinfstr(infstr, line);
4868 		}
4869 		return(returninfstr(infstr));
4870 	}
4871 
4872 	/* generate two-value description */
4873 	addstringtoinfstr(infstr, us_tecedmakefract(mul));
4874 	addtoinfstr(infstr, ',');
4875 	addstringtoinfstr(infstr, us_tecedmakefract(add));
4876 	return(returninfstr(infstr));
4877 }
4878 
4879 /****************************** WRITE TECHNOLOGY AS "JAVA" CODE ******************************/
4880 
4881 /*
4882  * routine to dump the layer information in technology "tech" to the stream in
4883  * "f".
4884  */
us_teceditdumpjavalayers(FILE * f,TECHNOLOGY * tech,CHAR * techname)4885 void us_teceditdumpjavalayers(FILE *f, TECHNOLOGY *tech, CHAR *techname)
4886 {
4887 	CHAR date[30], *transparent, *l1, *l2, *l3, *l4, *l5;
4888 	REGISTER INTBIG i, j, k, red, green, blue;
4889 	REGISTER void *infstr;
4890 	float r, c;
4891 	REGISTER BOOLEAN extrafunction;
4892 	REGISTER VARIABLE *varr, *varc;
4893 
4894 	/* write legal banner */
4895 	xprintf(f, x_("// BE SURE TO INCLUDE THIS TECHNOLOGY IN Technology.initAllTechnologies()\n\n"));
4896 	xprintf(f, x_("/* -*- tab-width: 4 -*-\n"));
4897 	xprintf(f, x_(" *\n"));
4898 	xprintf(f, x_(" * Electric(tm) VLSI Design System\n"));
4899 	xprintf(f, x_(" *\n"));
4900 	xprintf(f, x_(" * File: %s.java\n"), techname);
4901 	xprintf(f, x_(" * %s technology description\n"), techname);
4902 	xprintf(f, x_(" * Generated automatically from a library\n"));
4903 	xprintf(f, x_(" *\n"));
4904 	estrcpy(date, timetostring(getcurrenttime()));
4905 	date[24] = 0;
4906 	xprintf(f, x_(" * Copyright (c) %s Sun Microsystems and Static Free Software\n"), &date[20]);
4907 	xprintf(f, x_(" *\n"));
4908 	xprintf(f, x_(" * Electric(tm) is free software; you can redistribute it and/or modify\n"));
4909 	xprintf(f, x_(" * it under the terms of the GNU General Public License as published by\n"));
4910 	xprintf(f, x_(" * the Free Software Foundation; either version 2 of the License, or\n"));
4911 	xprintf(f, x_(" * (at your option) any later version.\n"));
4912 	xprintf(f, x_(" *\n"));
4913 	xprintf(f, x_(" * Electric(tm) is distributed in the hope that it will be useful,\n"));
4914 	xprintf(f, x_(" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"));
4915 	xprintf(f, x_(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"));
4916 	xprintf(f, x_(" * GNU General Public License for more details.\n"));
4917 	xprintf(f, x_(" *\n"));
4918 	xprintf(f, x_(" * You should have received a copy of the GNU General Public License\n"));
4919 	xprintf(f, x_(" * along with Electric(tm); see the file COPYING.  If not, write to\n"));
4920 	xprintf(f, x_(" * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,\n"));
4921 	xprintf(f, x_(" * Boston, Mass 02111-1307, USA.\n"));
4922 	xprintf(f, x_(" */\n"));
4923 	xprintf(f, x_("package com.sun.electric.technology.technologies;\n"));
4924 	xprintf(f, x_("\n"));
4925 
4926 	/* write header */
4927 	xprintf(f, x_("import com.sun.electric.technology.Technology;\n"));
4928 	xprintf(f, x_("import com.sun.electric.technology.Layer;\n"));
4929 	xprintf(f, x_("import com.sun.electric.technology.PrimitiveNode;\n"));
4930 	xprintf(f, x_("import com.sun.electric.technology.PrimitiveArc;\n"));
4931 	xprintf(f, x_("import com.sun.electric.technology.PrimitivePort;\n"));
4932 	xprintf(f, x_("import com.sun.electric.technology.EdgeH;\n"));
4933 	xprintf(f, x_("import com.sun.electric.technology.EdgeV;\n"));
4934 	xprintf(f, x_("import com.sun.electric.technology.SizeOffset;\n"));
4935 	xprintf(f, x_("import com.sun.electric.database.geometry.EGraphics;\n"));
4936 	xprintf(f, x_("import com.sun.electric.database.geometry.Poly;\n"));
4937 	xprintf(f, x_("import com.sun.electric.database.prototype.ArcProto;\n"));
4938 	xprintf(f, x_("import com.sun.electric.database.prototype.PortProto;\n"));
4939 	xprintf(f, x_("import com.sun.electric.database.prototype.NodeProto;\n"));
4940 	xprintf(f, x_("import com.sun.electric.tool.drc.DRC;\n"));
4941 	xprintf(f, x_("\n"));
4942 	xprintf(f, x_("import java.awt.Color;\n"));
4943 	xprintf(f, x_("\n"));
4944 
4945 	xprintf(f, x_("/**\n"));
4946 	xprintf(f, x_(" * This is the %s Technology.\n"), tech->techdescript);
4947 	xprintf(f, x_(" */\n"));
4948 	xprintf(f, x_("public class %s extends Technology\n"), techname);
4949 	xprintf(f, x_("{\n"), techname);
4950 	xprintf(f, x_("\t/** the %s Technology object. */	public static final %s tech = new %s();\n"),
4951 		tech->techdescript, techname, techname);
4952 	if ((us_tecflags&(HASCONDRC|HASUNCONDRC)) != 0)
4953 	{
4954 		xprintf(f, x_("\tprivate static final double XX = -1;\n"));
4955 		xprintf(f, x_("\tprivate double [] conDist, unConDist;\n"));
4956 	}
4957 	xprintf(f, x_("\n"));
4958 
4959 	xprintf(f, x_("\t// -------------------- private and protected methods ------------------------\n"));
4960 	xprintf(f, x_("\tprivate %s()\n"), techname);
4961 	xprintf(f, x_("\t{\n"));
4962 	xprintf(f, x_("\t\tsetTechName(\"%s\");\n"), techname);
4963 	xprintf(f, x_("\t\tsetTechDesc(\"%s\");\n"), tech->techdescript);
4964 	xprintf(f, x_("\t\tsetFactoryScale(%ld, true);   // in nanometers: really %g microns\n"),
4965 		tech->deflambda / 2, (float)tech->deflambda / 2000.0);
4966 	xprintf(f, x_("\t\tsetNoNegatedArcs();\n"));
4967 	xprintf(f, x_("\t\tsetStaticTechnology();\n"));
4968 
4969 	/* write the color map */
4970 	if ((us_tecflags&HASCOLORMAP) != 0)
4971 	{
4972 		/* determine the five transparent layers */
4973 		l1 = x_("layer 1");
4974 		l2 = x_("layer 2");
4975 		l3 = x_("layer 3");
4976 		l4 = x_("layer 4");
4977 		l5 = x_("layer 5");
4978 		for(i=0; i<tech->layercount; i++)
4979 		{
4980 			if (tech->layers[i]->bits == LAYERT1 && l1 == 0)
4981 				l1 = us_teclayer_names[i]; else
4982 			if (tech->layers[i]->bits == LAYERT2 && l2 == 0)
4983 				l2 = us_teclayer_names[i]; else
4984 			if (tech->layers[i]->bits == LAYERT3 && l3 == 0)
4985 				l3 = us_teclayer_names[i]; else
4986 			if (tech->layers[i]->bits == LAYERT4 && l4 == 0)
4987 				l4 = us_teclayer_names[i]; else
4988 			if (tech->layers[i]->bits == LAYERT5 && l5 == 0)
4989 				l5 = us_teclayer_names[i];
4990 		}
4991 		xprintf(f, x_("\t\tsetNumTransparentLayers(5);\n"));
4992 		xprintf(f, x_("\t\tsetFactoryTransparentLayers(new Color []\n"));
4993 		xprintf(f, x_("\t\t{\n"));
4994 		xprintf(f, x_("\t\t\tnew Color(%3d,%3d,%3d), // %s\n"),
4995 			us_teccolmap[1].red, us_teccolmap[1].green, us_teccolmap[1].blue, l1);
4996 		xprintf(f, x_("\t\t\tnew Color(%3d,%3d,%3d), // %s\n"),
4997 			us_teccolmap[2].red, us_teccolmap[2].green, us_teccolmap[2].blue, l2);
4998 		xprintf(f, x_("\t\t\tnew Color(%3d,%3d,%3d), // %s\n"),
4999 			us_teccolmap[4].red, us_teccolmap[4].green, us_teccolmap[4].blue, l3);
5000 		xprintf(f, x_("\t\t\tnew Color(%3d,%3d,%3d), // %s\n"),
5001 			us_teccolmap[8].red, us_teccolmap[8].green, us_teccolmap[8].blue, l4);
5002 		xprintf(f, x_("\t\t\tnew Color(%3d,%3d,%3d), // %s\n"),
5003 			us_teccolmap[16].red, us_teccolmap[16].green, us_teccolmap[16].blue, l5);
5004 		xprintf(f, x_("\t\t});\n"));
5005 	}
5006 	xprintf(f, x_("\n"));
5007 
5008 	/* write the layer declarations */
5009 	xprintf(f, x_("\t\t//**************************************** LAYERS ****************************************\n\n"));
5010 	for(i=0; i<tech->layercount; i++)
5011 	{
5012 		xprintf(f, x_("\t\t/** %s layer */\n"), us_teclayer_iname[i]);
5013 		xprintf(f, x_("\t\tLayer %s_lay = Layer.newInstance(this, \"%s\",\n"), us_teclayer_iname[i],
5014 			us_teclayer_names[i]);
5015 		xprintf(f, x_("\t\t\tnew EGraphics("));
5016 		if ((tech->layers[i]->colstyle&NATURE) == SOLIDC) xprintf(f, x_("EGraphics.SOLID")); else
5017 		{
5018 			if ((tech->layers[i]->colstyle&OUTLINEPAT) == 0)
5019 				xprintf(f, x_("EGraphics.PATTERNED")); else
5020 					xprintf(f, x_("EGraphics.OUTLINEPAT"));
5021 		}
5022 		xprintf(f, x_(", "));
5023 		if ((tech->layers[i]->bwstyle&NATURE) == SOLIDC) xprintf(f, x_("EGraphics.SOLID")); else
5024 		{
5025 			if ((tech->layers[i]->bwstyle&OUTLINEPAT) == 0)
5026 				xprintf(f, x_("EGraphics.PATTERNED")); else
5027 					xprintf(f, x_("EGraphics.OUTLINEPAT"));
5028 		}
5029 		transparent = "0";
5030 		switch (tech->layers[i]->bits)
5031 		{
5032 			case LAYERT1: transparent = "EGraphics.TRANSPARENT_1";   break;
5033 			case LAYERT2: transparent = "EGraphics.TRANSPARENT_2";   break;
5034 			case LAYERT3: transparent = "EGraphics.TRANSPARENT_3";   break;
5035 			case LAYERT4: transparent = "EGraphics.TRANSPARENT_4";   break;
5036 			case LAYERT5: transparent = "EGraphics.TRANSPARENT_5";   break;
5037 		}
5038 		red = us_teccolmap[tech->layers[i]->col].red;
5039 		green = us_teccolmap[tech->layers[i]->col].green;
5040 		blue = us_teccolmap[tech->layers[i]->col].blue;
5041 		if (red < 0 || red > 255) red = 0;
5042 		if (green < 0 || green > 255) green = 0;
5043 		if (blue < 0 || blue > 255) blue = 0;
5044 		xprintf(f, x_(", %s, %ld,%ld,%ld,0.8,1,\n"), transparent, red, green, blue);
5045 
5046 		for(j=0; j<16; j++) if (tech->layers[i]->raster[j] != 0) break;
5047 		if (j >= 16)
5048 			xprintf(f, x_("\t\t\tnew int[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}));\n\n")); else
5049 		{
5050 			for(j=0; j<16; j++)
5051 			{
5052 				xprintf(f, x_("\t\t\t"));
5053 				if (j == 0) xprintf(f, x_("new int[] { ")); else
5054 					xprintf(f, x_("\t\t\t"));
5055 				xprintf(f, x_("0x%04x"), tech->layers[i]->raster[j]&0xFFFF);
5056 				if (j == 15) xprintf(f, x_("}));")); else
5057 					xprintf(f, x_(",   "));
5058 
5059 				xprintf(f, x_("// "));
5060 				for(k=0; k<16; k++)
5061 					if ((tech->layers[i]->raster[j] & (1 << (15-k))) != 0)
5062 						xprintf(f, x_("X")); else xprintf(f, x_(" "));
5063 				xprintf(f, x_("\n"));
5064 			}
5065 			xprintf(f, x_("\n"));
5066 		}
5067 	}
5068 
5069 	/* write the layer functions */
5070 	xprintf(f, x_("\t\t// The layer functions\n"));
5071 	for(i=0; i<tech->layercount; i++)
5072 	{
5073 		k = us_teclayer_function[i];
5074 		infstr = initinfstr();
5075 		formatinfstr(infstr, x_("%s_lay.setFunction(Layer.Function."), us_teclayer_iname[i]);
5076 		if ((k&(LFTYPE|LFPTYPE)) == (LFDIFF|LFPTYPE))
5077 		{
5078 			addstringtoinfstr(infstr, "DIFFP");
5079 			k &= ~LFPTYPE;
5080 		} else if ((k&(LFTYPE|LFNTYPE)) == (LFDIFF|LFNTYPE))
5081 		{
5082 			addstringtoinfstr(infstr, "DIFFN");
5083 			k &= ~LFNTYPE;
5084 		} else if ((k&(LFTYPE|LFPTYPE)) == (LFWELL|LFPTYPE))
5085 		{
5086 			addstringtoinfstr(infstr, "WELLP");
5087 			k &= ~LFPTYPE;
5088 		} else if ((k&(LFTYPE|LFNTYPE)) == (LFWELL|LFNTYPE))
5089 		{
5090 			addstringtoinfstr(infstr, "WELLN");
5091 			k &= ~LFNTYPE;
5092 		} else if ((k&(LFTYPE|LFPTYPE)) == (LFIMPLANT|LFPTYPE))
5093 		{
5094 			addstringtoinfstr(infstr, "IMPLANTP");
5095 			k &= ~LFPTYPE;
5096 		} else if ((k&(LFTYPE|LFNTYPE)) == (LFIMPLANT|LFNTYPE))
5097 		{
5098 			addstringtoinfstr(infstr, "IMPLANTN");
5099 			k &= ~LFNTYPE;
5100 		} else if ((k&(LFTYPE|LFINTRANS)) == (LFPOLY1|LFINTRANS))
5101 		{
5102 			addstringtoinfstr(infstr, "GATE");
5103 			k &= ~LFINTRANS;
5104 		} else
5105 		{
5106 			addstringtoinfstr(infstr, &us_teclayer_functions[k&LFTYPE].constant[2]);
5107 		}
5108 		extrafunction = FALSE;
5109 		for(j=0; us_teclayer_functions[j].name != 0; j++)
5110 		{
5111 			if (us_teclayer_functions[j].value <= LFTYPE) continue;
5112 			if ((k&us_teclayer_functions[j].value) != 0)
5113 			{
5114 				if (extrafunction) addstringtoinfstr(infstr, "|"); else
5115 					addstringtoinfstr(infstr, ", ");
5116 				addstringtoinfstr(infstr, "Layer.Function.");
5117 				addstringtoinfstr(infstr, &us_teclayer_functions[j].constant[2]);
5118 				extrafunction = TRUE;
5119 			}
5120 		}
5121 		addstringtoinfstr(infstr, ");");
5122 		xprintf(f, x_("\t\t%s"), returninfstr(infstr));
5123 		xprintf(f, x_("\t\t// %s\n"), us_teclayer_names[i]);
5124 	}
5125 
5126 	/* write the CIF layer names */
5127 	if ((us_tecflags&HASCIF) != 0)
5128 	{
5129 		xprintf(f, x_("\n\t\t// The CIF names\n"));
5130 		for(i=0; i<tech->layercount; i++)
5131 		{
5132 			xprintf(f, x_("\t\t%s_lay.setFactoryCIFLayer(\""), us_teclayer_iname[i]);
5133 			if (us_teccif_layers[i] != 0) xprintf(f, x_("%s"), us_teccif_layers[i]);
5134 			xprintf(f, x_("\");\t\t// %s\n"), us_teclayer_names[i]);
5135 		}
5136 	}
5137 
5138 	/* write the DXF layer numbers */
5139 	if ((us_tecflags&HASDXF) != 0)
5140 	{
5141 		xprintf(f, x_("\n\t\t// The DXF names\n"));
5142 		for(i=0; i<tech->layercount; i++)
5143 		{
5144 			xprintf(f, x_("\t\t%s_lay.setFactoryDXFLayer(\""), us_teclayer_iname[i]);
5145 			xprintf(f, x_("%s"), us_tecdxf_layers[i]);
5146 			xprintf(f, x_("\");\t\t// %s\n"), us_teclayer_names[i]);
5147 		}
5148 	}
5149 
5150 	/* write the Calma GDS-II layer number */
5151 	if ((us_tecflags&HASGDS) != 0)
5152 	{
5153 		xprintf(f, x_("\n\t\t// The GDS names\n"));
5154 		for(i=0; i<tech->layercount; i++)
5155 		{
5156 			xprintf(f, x_("\t\t%s_lay.setFactoryGDSLayer(\""), us_teclayer_iname[i]);
5157 			xprintf(f, x_("%s"), us_tecgds_layers[i]);
5158 			xprintf(f, x_("\");\t\t// %s\n"), us_teclayer_names[i]);
5159 		}
5160 	}
5161 
5162 	/* write the 3D information */
5163 	if ((us_tecflags&HAS3DINFO) != 0)
5164 	{
5165 		xprintf(f, x_("\n\t\t// The layer height\n"));
5166 		for(i=0; i<tech->layercount; i++)
5167 		{
5168 			xprintf(f, x_("\t\t%s_lay.setFactory3DInfo("), us_teclayer_iname[i]);
5169 			xprintf(f, x_("%ld, %ld"), us_tec3d_thickness[i], us_tec3d_height[i]);
5170 			xprintf(f, x_(");\t\t// %s\n"), us_teclayer_names[i]);
5171 		}
5172 	}
5173 
5174 	/* write the SPICE information */
5175 	if ((us_tecflags&(HASSPIRES|HASSPICAP|HASSPIECAP)) != 0)
5176 	{
5177 		xprintf(f, x_("\n\t\t// The SPICE information\n"));
5178 		for(i=0; i<tech->layercount; i++)
5179 		{
5180 			xprintf(f, x_("\t\t%s_lay.setFactoryParasitics("), us_teclayer_iname[i]);
5181 			if ((us_tecflags&HASSPIRES) == 0) xprintf(f, x_("0, ")); else
5182 				xprintf(f, x_("%s, "), us_tecedmakefloatstring(us_tecspice_res[i]));
5183 			if ((us_tecflags&HASSPICAP) == 0) xprintf(f, x_("0, ")); else
5184 				xprintf(f, x_("%s, "), us_tecedmakefloatstring(us_tecspice_cap[i]));
5185 			if ((us_tecflags&HASSPIECAP) == 0) xprintf(f, x_("0")); else
5186 				xprintf(f, x_("%s"), us_tecedmakefloatstring(us_tecspice_ecap[i]));
5187 			xprintf(f, x_(");\t\t// %s\n"), us_teclayer_names[i]);
5188 		}
5189 	}
5190 	varr = getval((INTBIG)tech, VTECHNOLOGY, -1, x_("SIM_spice_min_resistance"));
5191 	varc = getval((INTBIG)tech, VTECHNOLOGY, -1, x_("SIM_spice_min_capacitance"));
5192 	if (varr != NOVARIABLE || varc != NOVARIABLE)
5193 	{
5194 		if (varr != NOVARIABLE) r = castfloat(varr->addr); else r = 0.0;
5195 		if (varc != NOVARIABLE) c = castfloat(varr->addr); else c = 0.0;
5196         xprintf(f, x_("\t\tsetFactoryParasitics(%g, %g);\n"), r, c);
5197 	}
5198 
5199 	/* write design rules */
5200 	if ((us_tecflags&(HASCONDRC|HASUNCONDRC)) != 0)
5201 	{
5202 		xprintf(f, x_("\n\t\t//******************** DESIGN RULES ********************\n"));
5203 
5204 		if ((us_tecflags&HASCONDRC) != 0)
5205 		{
5206 			xprintf(f, x_("\n\t\tconDist = new double[]\n"));
5207 			us_teceditdumpjavadrctab(f, us_tecdrc_rules->conlist, tech, FALSE);
5208 		}
5209 		if ((us_tecflags&HASUNCONDRC) != 0)
5210 		{
5211 			xprintf(f, x_("\n\t\tunConDist = new double[]\n"));
5212 			us_teceditdumpjavadrctab(f, us_tecdrc_rules->unconlist, tech, FALSE);
5213 		}
5214 	}
5215 }
5216 
us_teceditdumpjavadrctab(FILE * f,void * distances,TECHNOLOGY * tech,BOOLEAN isstring)5217 void us_teceditdumpjavadrctab(FILE *f, void *distances, TECHNOLOGY *tech, BOOLEAN isstring)
5218 {
5219 	REGISTER INTBIG i, j;
5220 	REGISTER INTBIG amt, *amtlist;
5221 	CHAR shortname[7], *msg, **distlist;
5222 
5223 	for(i=0; i<6; i++)
5224 	{
5225 		xprintf(f, x_("\t\t\t//            "));
5226 		for(j=0; j<tech->layercount; j++)
5227 		{
5228 			if ((INTBIG)estrlen(us_teclayer_iname[j]) <= i) xprintf(f, x_(" ")); else
5229 				xprintf(f, x_("%c"), us_teclayer_iname[j][i]);
5230 			xprintf(f, x_("  "));
5231 		}
5232 		xprintf(f, x_("\n"));
5233 	}
5234 	if (isstring) distlist = (CHAR **)distances; else
5235 		amtlist = (INTBIG *)distances;
5236 	for(j=0; j<tech->layercount; j++)
5237 	{
5238 		(void)estrncpy(shortname, us_teclayer_iname[j], 6);
5239 		shortname[6] = 0;
5240 		xprintf(f, x_("\t\t\t/* %-6s */ "), shortname);
5241 		for(i=0; i<j; i++) xprintf(f, x_("   "));
5242 		for(i=j; i<tech->layercount; i++)
5243 		{
5244 			if (isstring)
5245 			{
5246 				msg = *distlist++;
5247 				xprintf(f, x_("x_(\"%s\")"), msg);
5248 			} else
5249 			{
5250 				amt = *amtlist++;
5251 				if (amt < 0) xprintf(f, x_("XX")); else
5252 				{
5253 					xprintf(f, x_("%g"), (float)amt/WHOLE);
5254 				}
5255 			}
5256 			if (j != tech->layercount-1 || i != tech->layercount-1)
5257 				xprintf(f, x_(","));
5258 		}
5259 		xprintf(f, x_("\n"));
5260 	}
5261 	xprintf(f, x_("\t\t};\n"));
5262 }
5263 
5264 /*
5265  * routine to dump the arc information in technology "tech" to the stream in
5266  * "f".
5267  */
us_teceditdumpjavaarcs(FILE * f,TECHNOLOGY * tech,CHAR * techname)5268 void us_teceditdumpjavaarcs(FILE *f, TECHNOLOGY *tech, CHAR *techname)
5269 {
5270 	REGISTER INTBIG i, j, k;
5271 
5272 	/* print the header */
5273 	xprintf(f, x_("\n\t\t//******************** ARCS ********************\n"));
5274 
5275 	/* now write the arcs */
5276 	for(i=0; i<tech->arcprotocount; i++)
5277 	{
5278 		xprintf(f, x_("\n\t\t/** %s arc */\n"), tech->arcprotos[i]->arcname);
5279 		xprintf(f, x_("\t\tPrimitiveArc %s_arc = PrimitiveArc.newInstance(this, \"%s\", %g, new Technology.ArcLayer []\n"),
5280 			us_teceditconverttojava(tech->arcprotos[i]->arcname), tech->arcprotos[i]->arcname, (float)tech->arcprotos[i]->arcwidth/WHOLE);
5281 		xprintf(f, x_("\t\t{\n"));
5282 		for(k=0; k<tech->arcprotos[i]->laycount; k++)
5283 		{
5284 			xprintf(f, x_("\t\t\tnew Technology.ArcLayer(%s_lay, "),
5285 				us_teclayer_iname[tech->arcprotos[i]->list[k].lay]);
5286 			if (tech->arcprotos[i]->list[k].off == 0) xprintf(f, x_("0,")); else
5287 				xprintf(f, x_("%g,"), (float)tech->arcprotos[i]->list[k].off/WHOLE);
5288 			if (tech->arcprotos[i]->list[k].style == FILLED) xprintf(f, x_(" Poly.Type.FILLED)")); else
5289 				xprintf(f, x_(" Poly.Type.CLOSED)"));
5290 			if (k+1 < tech->arcprotos[i]->laycount) xprintf(f, x_(","));
5291 			xprintf(f, x_("\n"));
5292 		}
5293 		xprintf(f, x_("\t\t});\n"));
5294 		for(j=0; us_tecarc_functions[j].name != 0; j++)
5295 			if (us_tecarc_functions[j].value ==
5296 				(INTBIG)((tech->arcprotos[i]->initialbits&AFUNCTION)>>AFUNCTIONSH))
5297 		{
5298 			xprintf(f, x_("\t\t%s_arc.setFunction(PrimitiveArc.Function.%s);\n"),
5299 				us_teceditconverttojava(tech->arcprotos[i]->arcname), &us_tecarc_functions[j].constant[2]);
5300 			break;
5301 		}
5302 		if (us_tecarc_functions[j].name == 0)
5303 			xprintf(f, x_("\t\t%s_arc.setFunction(PrimitiveArc.Function.UNKNOWN);\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname));
5304 		if ((tech->arcprotos[i]->initialbits&CANWIPE) != 0)
5305 			xprintf(f, x_("\t\t%s_arc.setWipable();\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname));
5306 		if ((us_tecflags&HASARCWID) != 0 && us_tecarc_widoff[i] != 0)
5307 		{
5308 			xprintf(f, x_("\t\t%s_arc.setWidthOffset(%ld);\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname),
5309 				(float)us_tecarc_widoff[i]/WHOLE);
5310 		}
5311 
5312 		if ((tech->arcprotos[i]->initialbits&WANTFIXANG) != 0)
5313 			xprintf(f, x_("\t\t%s_arc.setFactoryFixedAngle(true);\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname));
5314 		if ((tech->arcprotos[i]->initialbits&WANTNOEXTEND) != 0)
5315 			xprintf(f, x_("\t\t%s_arc.setFactoryExtended(false);\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname));
5316 		xprintf(f, x_("\t\t%s_arc.setFactoryAngleIncrement(%ld);\n"), us_teceditconverttojava(tech->arcprotos[i]->arcname),
5317 			(tech->arcprotos[i]->initialbits&AANGLEINC)>>AANGLEINCSH);
5318 
5319 	}
5320 }
5321 
5322 /*
5323  * routine to dump the node information in technology "tech" to the stream in
5324  * "f".
5325  */
us_teceditdumpjavanodes(FILE * f,TECHNOLOGY * tech,CHAR * techname)5326 void us_teceditdumpjavanodes(FILE *f, TECHNOLOGY *tech, CHAR *techname)
5327 {
5328 	REGISTER RULE *r;
5329 	REGISTER INTBIG i, j, k, l, tot;
5330 	CHAR *ab;
5331 	REGISTER PCON *pc;
5332 	REGISTER BOOLEAN yaxis;
5333 	REGISTER TECH_POLYGON *plist;
5334 	REGISTER TECH_NODES *nlist;
5335 	REGISTER void *infstr;
5336 
5337 	/* make abbreviations for each node */
5338 	for(i=0; i<tech->nodeprotocount; i++)
5339 	{
5340 		(void)allocstring(&ab, makeabbrev(tech->nodeprotos[i]->nodename, FALSE), el_tempcluster);
5341 		tech->nodeprotos[i]->creation = (NODEPROTO *)ab;
5342 
5343 		/* loop until the name is unique */
5344 		for(;;)
5345 		{
5346 			/* see if a previously assigned abbreviation is the same */
5347 			for(j=0; j<i; j++)
5348 				if (namesame(ab, (CHAR *)tech->nodeprotos[j]->creation) == 0) break;
5349 			if (j == i) break;
5350 
5351 			/* name conflicts: change it */
5352 			l = estrlen(ab);
5353 			if (ab[l-1] >= '0' && ab[l-1] <= '8') ab[l-1]++; else
5354 			{
5355 				infstr = initinfstr();
5356 				addstringtoinfstr(infstr, ab);
5357 				addtoinfstr(infstr, '0');
5358 				(void)reallocstring(&ab, returninfstr(infstr), el_tempcluster);
5359 				tech->nodeprotos[i]->creation = (NODEPROTO *)ab;
5360 			}
5361 		}
5362 	}
5363 
5364 	xprintf(f, x_("\n\t\t//******************** RECTANGLE DESCRIPTIONS ********************"));
5365 	xprintf(f, x_("\n\n"));
5366 
5367 	/* print box information */
5368 	i = 1;
5369 	for(r = us_tecedfirstrule; r != NORULE; r = r->nextrule)
5370 	{
5371 		if (!r->used) continue;
5372 		r->rindex = i++;
5373 		xprintf(f, x_("\t\tTechnology.TechPoint [] box_%ld = new Technology.TechPoint[] {\n"),
5374 			r->rindex);
5375 		for(j=0; j<r->count; j += 2)
5376 		{
5377 			if ((j%4) == 0)
5378 			{
5379 				yaxis = FALSE;
5380 				xprintf(f, x_("\t\t\tnew Technology.TechPoint("));
5381 			} else
5382 			{
5383 				yaxis = TRUE;
5384 			}
5385 			xprintf(f, x_("%s"), us_tecededgelabeljava(r->value[j], r->value[j+1], yaxis));
5386 			if ((j%4) == 0) xprintf(f, x_(", ")); else
5387 			{
5388 				xprintf(f, x_(")"));
5389 				if (j+1 < r->count) xprintf(f, x_(","));
5390 				xprintf(f, x_("\n"));
5391 			}
5392 		}
5393 		xprintf(f, x_("\t\t};\n"));
5394 	}
5395 
5396 	xprintf(f, x_("\n\t\t//******************** NODES ********************\n"));
5397 
5398 	/* print node information */
5399 	for(i=0; i<tech->nodeprotocount; i++)
5400 	{
5401 		/* header comment */
5402 		nlist = tech->nodeprotos[i];
5403 		ab = (CHAR *)nlist->creation;
5404 		xprintf(f, x_("\n\t\t/** %s */\n"), nlist->nodename);
5405 
5406 		xprintf(f, x_("\t\tPrimitiveNode %s_node = PrimitiveNode.newInstance(\"%s\", this, %g, %g, "),
5407 			ab, nlist->nodename, (float)nlist->xsize/WHOLE, (float)nlist->ysize/WHOLE);
5408 		if (us_tecnode_widoff[i*4] != 0 || us_tecnode_widoff[i*4+1] != 0 ||
5409 			us_tecnode_widoff[i*4+2] != 0 || us_tecnode_widoff[i*4+3] != 0)
5410 		{
5411 			xprintf(f, x_("new SizeOffset(%g, %g, %g, %g),\n"),
5412 				(float)us_tecnode_widoff[i*4] / WHOLE, (float)us_tecnode_widoff[i*4+1] / WHOLE,
5413 				(float)us_tecnode_widoff[i*4+2] / WHOLE, (float)us_tecnode_widoff[i*4+3] / WHOLE);
5414 		} else
5415 		{
5416 			xprintf(f, x_("null,\n"));
5417 		}
5418 
5419 		/* print layers */
5420 		xprintf(f, x_("\t\t\tnew Technology.NodeLayer []\n"));
5421 		xprintf(f, x_("\t\t\t{\n"));
5422 		tot = nlist->layercount;
5423 		for(j=0; j<tot; j++)
5424 		{
5425 			if (nlist->special == SERPTRANS) plist = &nlist->gra[j].basics; else
5426 				plist = &nlist->layerlist[j];
5427 			xprintf(f, x_("\t\t\t\tnew Technology.NodeLayer(%s_lay, %ld, Poly.Type."),
5428 				us_teclayer_iname[plist->layernum], plist->portnum);
5429 			switch (plist->style)
5430 			{
5431 				case FILLEDRECT:     xprintf(f, x_("FILLED,"));         break;
5432 				case CLOSEDRECT:     xprintf(f, x_("CLOSED,"));         break;
5433 				case CROSSED:        xprintf(f, x_("CROSSED,"));        break;
5434 				case FILLED:         xprintf(f, x_("FILLED,"));         break;
5435 				case CLOSED:         xprintf(f, x_("CLOSED,"));         break;
5436 				case OPENED:         xprintf(f, x_("OPENED,"));         break;
5437 				case OPENEDT1:       xprintf(f, x_("OPENEDT1,"));       break;
5438 				case OPENEDT2:       xprintf(f, x_("OPENEDT2,"));       break;
5439 				case OPENEDT3:       xprintf(f, x_("OPENEDT3,"));       break;
5440 				case VECTORS:        xprintf(f, x_("VECTORS,"));        break;
5441 				case CIRCLE:         xprintf(f, x_("CIRCLE,"));         break;
5442 				case THICKCIRCLE:    xprintf(f, x_("THICKCIRCLE,"));    break;
5443 				case DISC:           xprintf(f, x_("DISC,"));           break;
5444 				case CIRCLEARC:      xprintf(f, x_("CIRCLEARC,"));      break;
5445 				case THICKCIRCLEARC: xprintf(f, x_("THICKCIRCLEARC,")); break;
5446 				case TEXTCENT:       xprintf(f, x_("TEXTCENT,"));       break;
5447 				case TEXTTOP:        xprintf(f, x_("TEXTTOP,"));        break;
5448 				case TEXTBOT:        xprintf(f, x_("TEXTBOT,"));        break;
5449 				case TEXTLEFT:       xprintf(f, x_("TEXTLEFT,"));       break;
5450 				case TEXTRIGHT:      xprintf(f, x_("TEXTRIGHT,"));      break;
5451 				case TEXTTOPLEFT:    xprintf(f, x_("TEXTTOPLEFT,"));    break;
5452 				case TEXTBOTLEFT:    xprintf(f, x_("TEXTBOTLEFT,"));    break;
5453 				case TEXTTOPRIGHT:   xprintf(f, x_("TEXTTOPRIGHT,"));   break;
5454 				case TEXTBOTRIGHT:   xprintf(f, x_("TEXTBOTRIGHT,"));   break;
5455 				case TEXTBOX:        xprintf(f, x_("TEXTBOX,"));        break;
5456 				default:             xprintf(f, x_("????,"));           break;
5457 			}
5458 			switch (plist->representation)
5459 			{
5460 				case BOX:    xprintf(f, x_(" Technology.NodeLayer.BOX,"));     break;
5461 				case MINBOX: xprintf(f, x_(" Technology.NodeLayer.MINBOX,"));  break;
5462 				case POINTS: xprintf(f, x_(" Technology.NodeLayer.POINTS,"));  break;
5463 				default:     xprintf(f, x_(" Technology.NodeLayer.????,"));    break;
5464 			}
5465 			for(r = us_tecedfirstrule; r != NORULE; r = r->nextrule)
5466 				if (r->value == plist->points) break;
5467 			if (r != NORULE)
5468 			{
5469 				xprintf(f, x_(" box_%ld"), r->rindex);
5470 			} else
5471 				xprintf(f, x_(" box??"));
5472 			if (nlist->special == SERPTRANS)
5473 			{
5474 				xprintf(f, x_(", %g, %g, %g, %g"),
5475 					nlist->gra[j].lwidth / (float)WHOLE, nlist->gra[j].rwidth / (float)WHOLE,
5476 					nlist->gra[j].extendb / (float)WHOLE, nlist->gra[j].extendt / (float)WHOLE);
5477 			}
5478 			xprintf(f, x_(")"));
5479 			if (j+1 < tot) xprintf(f, x_(","));
5480 			xprintf(f, x_("\n"));
5481 		}
5482 		xprintf(f, x_("\t\t\t});\n"));
5483 
5484 		/* print ports */
5485 		xprintf(f, x_("\t\t%s_node.addPrimitivePorts(new PrimitivePort[]\n"), ab);
5486 		xprintf(f, x_("\t\t\t{\n"));
5487 		for(j=0; j<nlist->portcount; j++)
5488 		{
5489 			xprintf(f, x_("	\t\t\tPrimitivePort.newInstance(this, %s_node, new ArcProto [] {"), ab);
5490 			for(pc = us_tecedfirstpcon; pc != NOPCON; pc = pc->nextpcon)
5491 				if (pc->connects == nlist->portlist[j].portarcs) break;
5492 			if (pc != NOPCON)
5493 			{
5494 				for(l=0; l<pc->total; l++)
5495 				{
5496 					k = pc->connects[l+1];
5497 					xprintf(f, x_("%s_arc"), us_teceditconverttojava(tech->arcprotos[k]->arcname));
5498 					if (l+1 < pc->total) xprintf(f, x_(", "));
5499 				}
5500 			}
5501 			xprintf(f, x_("}, \"%s\", %ld,%ld, %ld, PortProto.Characteristic.UNKNOWN,\n"),
5502 				nlist->portlist[j].protoname,
5503 				(nlist->portlist[j].initialbits&PORTANGLE)>>PORTANGLESH,
5504 				(nlist->portlist[j].initialbits&PORTARANGE)>>PORTARANGESH,
5505 				(nlist->portlist[j].initialbits&PORTNET)>>PORTNETSH);
5506 			xprintf(f, x_("\t\t\t\t\t%s, %s, %s, %s)"),
5507 				us_tecededgelabeljava(nlist->portlist[j].lowxmul, nlist->portlist[j].lowxsum, FALSE),
5508 				us_tecededgelabeljava(nlist->portlist[j].lowymul, nlist->portlist[j].lowysum, TRUE),
5509 				us_tecededgelabeljava(nlist->portlist[j].highxmul, nlist->portlist[j].highxsum, FALSE),
5510 				us_tecededgelabeljava(nlist->portlist[j].highymul, nlist->portlist[j].highysum, TRUE));
5511 
5512 			if (j+1 < nlist->portcount) xprintf(f, x_(","));
5513 			xprintf(f, x_("\n"));
5514 		}
5515 		xprintf(f, x_("\t\t\t});\n"));
5516 
5517 		/* print the node information */
5518 		j = (nlist->initialbits&NFUNCTION)>>NFUNCTIONSH;
5519 		if (j < 0 || j >= MAXNODEFUNCTION) j = 0;
5520 		xprintf(f, x_("\t\t%s_node.setFunction(NodeProto.Function.%s);\n"), ab, &nodefunctionconstantname(j)[2]);
5521 
5522 		if ((nlist->initialbits&WIPEON1OR2) != 0)
5523 			xprintf(f, x_("\t\t%s_node.setWipeOn1or2();\n"), ab);
5524 		if ((nlist->initialbits&HOLDSTRACE) != 0)
5525 			xprintf(f, x_("\t\t%s_node.setHoldsOutline();\n"), ab);
5526 		if ((nlist->initialbits&NSQUARE) != 0)
5527 			xprintf(f, x_("\t\t%s_node.setSquare();\n"), ab);
5528 		if ((nlist->initialbits&ARCSWIPE) != 0)
5529 			xprintf(f, x_("\t\t%s_node.setArcsWipe();\n"), ab);
5530 		if ((nlist->initialbits&ARCSHRINK) != 0)
5531 			xprintf(f, x_("\t\t%s_node.setArcsShrink();\n"), ab);
5532 		if ((nlist->initialbits&NODESHRINK) != 0)
5533 			xprintf(f, x_("\t\t%s_node.setCanShrink();\n"), ab);
5534 		if ((nlist->initialbits&LOCKEDPRIM) != 0)
5535 			xprintf(f, x_("\t\t%s_node.setLockedPrim();\n"), ab);
5536 		if (nlist->special != 0)
5537 		{
5538 			switch (nlist->special)
5539 			{
5540 				case SERPTRANS:
5541 					xprintf(f, x_("\t\t%s_node.setSpecialType(PrimitiveNode.SERPTRANS);\n"), ab);
5542 					xprintf(f, x_("\t\t%s_node.setSpecialValues(new double [] {%g, %g, %g, %g, %g, %g});\n"),
5543 						ab, (float)nlist->f1/WHOLE, (float)nlist->f2/WHOLE, (float)nlist->f3/WHOLE,
5544 							(float)nlist->f4/WHOLE, (float)nlist->f5/WHOLE, (float)nlist->f6/WHOLE);
5545 					break;
5546 				case POLYGONAL:
5547 					xprintf(f, x_("\t\t%s_node.setSpecialType(PrimitiveNode.POLYGONAL);\n"), ab);
5548 					break;
5549 				case MULTICUT:
5550 					xprintf(f, x_("\t\t%s_node.setSpecialType(PrimitiveNode.MULTICUT);\n"), ab);
5551 					xprintf(f, x_("\t\t%s_node.setSpecialValues(new double [] {%g, %g, %g, %g});\n"),
5552 						ab, (float)nlist->f1/WHOLE, (float)nlist->f2/WHOLE, (float)nlist->f3/WHOLE,
5553 							(float)nlist->f4/WHOLE);
5554 					break;
5555 			}
5556 		}
5557 	}
5558 
5559 	/* write the pure-layer associations */
5560 	xprintf(f, x_("\n\t\t// The pure layer nodes\n"));
5561 	for(i=0; i<tech->layercount; i++)
5562 	{
5563 		if ((us_teclayer_function[i]&LFPSEUDO) != 0) continue;
5564 
5565 		/* find the pure layer node */
5566 		for(j=0; j<tech->nodeprotocount; j++)
5567 		{
5568 			nlist = tech->nodeprotos[j];
5569 			if (((nlist->initialbits&NFUNCTION)>>NFUNCTIONSH) != NPNODE) continue;
5570 			plist = &nlist->layerlist[0];
5571 			if (plist->layernum == i) break;
5572 		}
5573 		if (j >= tech->nodeprotocount) continue;
5574 		ab = (CHAR *)tech->nodeprotos[j]->creation;
5575 		xprintf(f, x_("\t\t%s_lay.setPureLayerNode("), us_teclayer_iname[i]);
5576 		xprintf(f, x_("%s_node"), ab);
5577 		xprintf(f, x_(");\t\t// %s\n"), us_teclayer_names[i]);
5578 	}
5579 
5580 	xprintf(f, x_("\t};\n"));
5581 
5582 #if 0
5583 	/* print grab point informaton if it exists */
5584 	if ((us_tecflags&HASGRAB) != 0 && us_tecnode_grabcount > 0)
5585 	{
5586 		xprintf(f, x_("\nstatic INTBIG %s_centergrab[] = {\n"), us_tecedmakesymbol(techname));
5587 		for(i=0; i<us_tecnode_grabcount; i += 3)
5588 		{
5589 			ab = (CHAR *)tech->nodeprotos[us_tecnode_grab[i]-1]->creation;
5590 			xprintf(f, x_("\tN%s, %ld, %ld"), us_tecedmakeupper(ab), us_tecnode_grab[i+1],
5591 				us_tecnode_grab[i+2]);
5592 			if (i != us_tecnode_grabcount-3) xprintf(f, x_(",\n"));
5593 		}
5594 		xprintf(f, x_("\n};\n"));
5595 	}
5596 
5597 	/* print minimum node size informaton if it exists */
5598 	if ((us_tecflags&HASMINNODE) != 0)
5599 	{
5600 		xprintf(f, x_("\nstatic INTBIG %s_node_minsize[NODEPROTOCOUNT*2] = {\n"), us_tecedmakesymbol(techname));
5601 		for(i=0; i<tech->nodeprotocount; i++)
5602 		{
5603 			if (us_tecdrc_rules->minnodesize[i*2] < 0) ab = x_("XX"); else
5604 				ab = us_tecedmakefract(us_tecdrc_rules->minnodesize[i*2]);
5605 			xprintf(f, x_("\t%s, "), ab);
5606 			if (us_tecdrc_rules->minnodesize[i*2+1] < 0) ab = x_("XX"); else
5607 				ab = us_tecedmakefract(us_tecdrc_rules->minnodesize[i*2+1]);
5608 			xprintf(f, x_("%s"), ab);
5609 			if (i == tech->nodeprotocount-1) ab = x_(""); else ab = x_(",");
5610 			xprintf(f, x_("%s\t\t/* %s */\n"), ab, tech->nodeprotos[i]->nodename);
5611 		}
5612 		xprintf(f, x_("};\n"));
5613 	}
5614 	if ((us_tecflags&HASMINNODER) != 0)
5615 	{
5616 		xprintf(f, x_("\nstatic char *%s_node_minsize_rule[NODEPROTOCOUNT] = {\n"), us_tecedmakesymbol(techname));
5617 		for(i=0; i<tech->nodeprotocount; i++)
5618 		{
5619 			if (i == tech->nodeprotocount-1) ab = x_(""); else ab = x_(",");
5620 			xprintf(f, x_("\tx_(\"%s\")%s\t\t/* %s */\n"), us_tecdrc_rules->minnodesizeR[i], ab,
5621 				tech->nodeprotos[i]->nodename);
5622 		}
5623 		xprintf(f, x_("};\n"));
5624 	}
5625 #endif
5626 
5627 	/* write method to reset rules */
5628 	if ((us_tecflags&(HASCONDRC|HASUNCONDRC)) != 0)
5629 	{
5630 		CHAR *conword, *unconword;
5631 		if ((us_tecflags&HASCONDRC) != 0) conword = "conDist"; else conword = "null";
5632 		if ((us_tecflags&HASUNCONDRC) != 0) unconword = "unConDist"; else unconword = "null";
5633 		xprintf(f, x_("\tpublic DRC.Rules getFactoryDesignRules()\n"));
5634 		xprintf(f, x_("\t{\n"));
5635 		xprintf(f, x_("\t\treturn DRC.makeSimpleRules(this, %s, %s);\n"), conword, unconword);
5636 		xprintf(f, x_("\t}\n"));
5637 	}
5638 
5639 	/* clean up */
5640 	for(i=0; i<tech->nodeprotocount; i++)
5641 	{
5642 		efree((CHAR *)tech->nodeprotos[i]->creation);
5643 		tech->nodeprotos[i]->creation = NONODEPROTO;
5644 	}
5645 }
5646 
5647 /*
5648  * Routine to remove illegal Java charcters from "string".
5649  */
us_teceditconverttojava(CHAR * string)5650 CHAR *us_teceditconverttojava(CHAR *string)
5651 {
5652 	REGISTER void *infstr;
5653 	REGISTER CHAR *pt;
5654 
5655 	infstr = initinfstr();
5656 	for(pt = string; *pt != 0; pt++)
5657 	{
5658 		if (*pt == '-') addtoinfstr(infstr, '_'); else
5659 			addtoinfstr(infstr, *pt);
5660 	}
5661 	return(returninfstr(infstr));
5662 }
5663 
5664 /*
5665  * routine to convert the multiplication and addition factors in "mul" and
5666  * "add" into proper constant names.  The "yaxis" is false for X and 1 for Y
5667  */
us_tecededgelabeljava(INTBIG mul,INTBIG add,BOOLEAN yaxis)5668 CHAR *us_tecededgelabeljava(INTBIG mul, INTBIG add, BOOLEAN yaxis)
5669 {
5670 	REGISTER INTBIG amt;
5671 	REGISTER void *infstr;
5672 
5673 	infstr = initinfstr();
5674 
5675 	/* handle constant distance from center */
5676 	if (mul == 0)
5677 	{
5678 		if (yaxis) addstringtoinfstr(infstr, "EdgeV."); else
5679 			addstringtoinfstr(infstr, "EdgeH.");
5680 		if (add == 0)
5681 		{
5682 			addstringtoinfstr(infstr, x_("makeCenter()"));
5683 		} else
5684 		{
5685 			formatinfstr(infstr, x_("fromCenter(%g)"), (float)add/WHOLE);
5686 		}
5687 		return(returninfstr(infstr));
5688 	}
5689 
5690 	/* handle constant distance from edge */
5691 	if ((mul == H0 || mul == -H0))
5692 	{
5693 		if (yaxis) addstringtoinfstr(infstr, "EdgeV."); else
5694 			addstringtoinfstr(infstr, "EdgeH.");
5695 		amt = abs(add);
5696 		if (!yaxis)
5697 		{
5698 			if (mul < 0)
5699 			{
5700 				if (add == 0) addstringtoinfstr(infstr, x_("makeLeftEdge()")); else
5701 					formatinfstr(infstr, x_("fromLeft(%g)"), (float)amt/WHOLE);
5702 			} else
5703 			{
5704 				if (add == 0) addstringtoinfstr(infstr, x_("makeRightEdge()")); else
5705 					formatinfstr(infstr, x_("fromRight(%g)"), (float)amt/WHOLE);
5706 			}
5707 		} else
5708 		{
5709 			if (mul < 0)
5710 			{
5711 				if (add == 0) addstringtoinfstr(infstr, x_("makeBottomEdge()")); else
5712 					formatinfstr(infstr, x_("fromBottom(%g)"), (float)amt/WHOLE);
5713 			} else
5714 			{
5715 				if (add == 0) addstringtoinfstr(infstr, x_("makeTopEdge()")); else
5716 					formatinfstr(infstr, x_("fromTop(%g)"), (float)amt/WHOLE);
5717 			}
5718 		}
5719 		return(returninfstr(infstr));
5720 	}
5721 
5722 	/* generate two-value description */
5723 	if (!yaxis)
5724 		formatinfstr(infstr, x_("new EdgeH(%g, %g)"), (float)mul/WHOLE, (float)add/WHOLE); else
5725 		formatinfstr(infstr, x_("new EdgeV(%g, %g)"), (float)mul/WHOLE, (float)add/WHOLE);
5726 	return(returninfstr(infstr));
5727 }
5728 
5729 /****************************** SUPPORT FOR SOURCE-CODE GENERATION ******************************/
5730 
5731 /*
5732  * Routine to return a string representation of the floating point value "v".
5733  * The letter "f" is added to the end if appropriate.
5734  */
us_tecedmakefloatstring(float v)5735 CHAR *us_tecedmakefloatstring(float v)
5736 {
5737 	static CHAR retstr[50];
5738 	REGISTER CHAR *pt;
5739 
5740 	esnprintf(retstr, 50, x_("%g"), v);
5741 	if (estrcmp(retstr, x_("0")) == 0) return(retstr);
5742 	for(pt = retstr; *pt != 0; pt++)
5743 		if (*pt == '.') break;
5744 	if (*pt == 0) estrcat(retstr, x_(".0"));
5745 	estrcat(retstr, x_("f"));
5746 	return(retstr);
5747 }
5748 
5749 /*
5750  * routine to convert the fractional value "amt" to a technology constant.
5751  * The presumption is that quarter values exist from K0 to K10, that
5752  * half values exist up to K20, that whole values exist up to K30, and
5753  * that other values are not necessarily defined in "tech.h".
5754  */
us_tecedmakefract(INTBIG amt)5755 CHAR *us_tecedmakefract(INTBIG amt)
5756 {
5757 	static CHAR line[21];
5758 	REGISTER INTBIG whole;
5759 	REGISTER CHAR *pt;
5760 
5761 	pt = line;
5762 	if (amt < 0)
5763 	{
5764 		*pt++ = '-';
5765 		amt = -amt;
5766 	}
5767 	whole = amt/WHOLE;
5768 	switch (amt%WHOLE)
5769 	{
5770 		case 0:
5771 			if (whole <= 30) (void)esnprintf(pt, 20, x_("K%ld"), whole); else
5772 				(void)esnprintf(pt, 20, x_("%ld"), amt);
5773 			break;
5774 		case Q0:
5775 			if (whole <= 10) (void)esnprintf(pt, 20, x_("Q%ld"), whole); else
5776 				(void)esnprintf(pt, 20, x_("%ld"), amt);
5777 			break;
5778 		case H0:
5779 			if (whole <= 20) (void)esnprintf(pt, 20, x_("H%ld"), whole); else
5780 				(void)esnprintf(pt, 20, x_("%ld"), amt);
5781 			break;
5782 		case T0:
5783 			if (whole <= 10) (void)esnprintf(pt, 20, x_("T%ld"), whole); else
5784 				(void)esnprintf(pt, 20, x_("%ld"), amt);
5785 			break;
5786 		default:
5787 			(void)esnprintf(pt, 20, x_("%ld"), amt);
5788 			break;
5789 	}
5790 	return(line);
5791 }
5792 
5793 /*
5794  * routine to convert all characters in string "str" to upper case and to
5795  * change any nonalphanumeric characters to a "_"
5796  */
us_tecedmakeupper(CHAR * str)5797 CHAR *us_tecedmakeupper(CHAR *str)
5798 {
5799 	REGISTER CHAR ch;
5800 	REGISTER void *infstr;
5801 
5802 	infstr = initinfstr();
5803 	while (*str != 0)
5804 	{
5805 		ch = *str++;
5806 		if (islower(ch)) ch = toupper(ch);
5807 		if (!isalnum(ch)) ch = '_';
5808 		addtoinfstr(infstr, ch);
5809 	}
5810 	return(returninfstr(infstr));
5811 }
5812 
5813 /*
5814  * routine to change any nonalphanumeric characters in string "str" to a "_"
5815  */
us_tecedmakesymbol(CHAR * str)5816 CHAR *us_tecedmakesymbol(CHAR *str)
5817 {
5818 	REGISTER CHAR ch;
5819 	REGISTER void *infstr;
5820 
5821 	infstr = initinfstr();
5822 	while (*str != 0)
5823 	{
5824 		ch = *str++;
5825 		if (!isalnum(ch)) ch = '_';
5826 		addtoinfstr(infstr, ch);
5827 	}
5828 	return(returninfstr(infstr));
5829 }
5830 
5831 /*
5832  * Routine to find the parameter value in a string that has been stored as a message
5833  * on a node.  These parameters always have the form "name: value".  This returns a pointer
5834  * to the "value" part.
5835  */
us_teceditgetparameter(VARIABLE * var)5836 CHAR *us_teceditgetparameter(VARIABLE *var)
5837 {
5838 	REGISTER CHAR *str, *orig;
5839 
5840 	orig = str = (CHAR *)var->addr;
5841 	while (*str != 0 && *str != ':') str++;
5842 	if (*str == 0) return(orig);
5843 	*str++;
5844 	while (*str == ' ') str++;
5845 	return(str);
5846 }
5847 
5848 /*
5849  * Routine to return the name of the technology-edit port on node "ni".  Typically,
5850  * this is stored on the "EDTEC_portname" variable, but it may also be the node's name.
5851  */
us_tecedgetportname(NODEINST * ni)5852 CHAR *us_tecedgetportname(NODEINST *ni)
5853 {
5854 	REGISTER VARIABLE *var;
5855 
5856 	var = getval((INTBIG)ni, VNODEINST, VSTRING, x_("EDTEC_portname"));
5857 	if (var != NOVARIABLE) return((CHAR *)var->addr);
5858 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
5859 	if (var != NOVARIABLE) return((CHAR *)var->addr);
5860 	return(0);
5861 }
5862