1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usredtecc.c
6  * User interface technology editor: interactive technology library editing
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 "edialogs.h"
36 #include "usr.h"
37 #include "drc.h"
38 #include "tecgen.h"
39 #include "tecart.h"
40 #include "usredtec.h"
41 #include "usrdiacom.h"
42 
43 #define MAXNAMELEN 25		/* max chars in a new name */
44 
45 INTBIG us_teceddrclayers = 0;
46 CHAR **us_teceddrclayernames = 0;
47 
48 /* the known technology variables */
49 TECHVAR us_knownvars[] =
50 {
51 	{x_("DRC_ecad_deck"),               NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING|VISARRAY,
52 		x_("Dracula design-rule deck")},
53 	{x_("IO_cif_polypoints"),           NOTECHVAR, 0, 0, 0.0, x_(""), VINTEGER,
54 		x_("Maximum points in a CIF polygon")},
55 	{x_("IO_cif_resolution"),           NOTECHVAR, 0, 0, 0.0, x_(""), VINTEGER,
56 		x_("Minimum resolution of CIF coordinates")},
57 	{x_("IO_gds_polypoints"),           NOTECHVAR, 0, 0, 0.0, x_(""), VINTEGER,
58 		x_("Maximum points in a GDS-II polygon")},
59 	{x_("SIM_spice_min_resistance"),    NOTECHVAR, 0, 0, 0.0, x_(""), VFLOAT,
60 		x_("Minimum resistance of SPICE elements")},
61 	{x_("SIM_spice_min_capacitance"),   NOTECHVAR, 0, 0, 0.0, x_(""), VFLOAT,
62 		x_("Minimum capacitance of SPICE elements")},
63 	{x_("SIM_spice_mask_scale"),        NOTECHVAR, 0, 0, 0.0, x_(""), VFLOAT,
64 		x_("Scaling factor for SPICE decks")},
65 	{x_("SIM_spice_header_level1"),     NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING|VISARRAY,
66 		x_("Level 1 header for SPICE decks")},
67 	{x_("SIM_spice_header_level2"),     NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING|VISARRAY,
68 		x_("Level 2 header for SPICE decks")},
69 	{x_("SIM_spice_header_level3"),     NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING|VISARRAY,
70 		x_("Level 3 header for SPICE decks")},
71 	{x_("SIM_spice_model_file"),        NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING,
72 		x_("Disk file with SPICE header cards")},
73 	{x_("SIM_spice_trailer_file"),      NOTECHVAR, 0, 0, 0.0, x_(""), VSTRING,
74 		x_("Disk file with SPICE trailer cards")},
75 	{NULL, NULL,0, 0, 0.0, NULL, 0, NULL}  /* 0 */
76 };
77 
78 /* these must correspond to the layer functions in "efunction.h" */
79 LIST us_teclayer_functions[] =
80 {
81 	{x_("unknown"),           x_("LFUNKNOWN"),     LFUNKNOWN},
82 	{x_("metal-1"),           x_("LFMETAL1"),      LFMETAL1},
83 	{x_("metal-2"),           x_("LFMETAL2"),      LFMETAL2},
84 	{x_("metal-3"),           x_("LFMETAL3"),      LFMETAL3},
85 	{x_("metal-4"),           x_("LFMETAL4"),      LFMETAL4},
86 	{x_("metal-5"),           x_("LFMETAL5"),      LFMETAL5},
87 	{x_("metal-6"),           x_("LFMETAL6"),      LFMETAL6},
88 	{x_("metal-7"),           x_("LFMETAL7"),      LFMETAL7},
89 	{x_("metal-8"),           x_("LFMETAL8"),      LFMETAL8},
90 	{x_("metal-9"),           x_("LFMETAL9"),      LFMETAL9},
91 	{x_("metal-10"),          x_("LFMETAL10"),     LFMETAL10},
92 	{x_("metal-11"),          x_("LFMETAL11"),     LFMETAL11},
93 	{x_("metal-12"),          x_("LFMETAL12"),     LFMETAL12},
94 	{x_("poly-1"),            x_("LFPOLY1"),       LFPOLY1},
95 	{x_("poly-2"),            x_("LFPOLY2"),       LFPOLY2},
96 	{x_("poly-3"),            x_("LFPOLY3"),       LFPOLY3},
97 	{x_("gate"),              x_("LFGATE"),        LFGATE},
98 	{x_("diffusion"),         x_("LFDIFF"),        LFDIFF},
99 	{x_("implant"),           x_("LFIMPLANT"),     LFIMPLANT},
100 	{x_("contact-1"),         x_("LFCONTACT1"),    LFCONTACT1},
101 	{x_("contact-2"),         x_("LFCONTACT2"),    LFCONTACT2},
102 	{x_("contact-3"),         x_("LFCONTACT3"),    LFCONTACT3},
103 	{x_("contact-4"),         x_("LFCONTACT4"),    LFCONTACT4},
104 	{x_("contact-5"),         x_("LFCONTACT5"),    LFCONTACT5},
105 	{x_("contact-6"),         x_("LFCONTACT6"),    LFCONTACT6},
106 	{x_("contact-7"),         x_("LFCONTACT7"),    LFCONTACT7},
107 	{x_("contact-8"),         x_("LFCONTACT8"),    LFCONTACT8},
108 	{x_("contact-9"),         x_("LFCONTACT9"),    LFCONTACT9},
109 	{x_("contact-10"),        x_("LFCONTACT10"),   LFCONTACT10},
110 	{x_("contact-11"),        x_("LFCONTACT11"),   LFCONTACT11},
111 	{x_("contact-12"),        x_("LFCONTACT12"),   LFCONTACT12},
112 	{x_("plug"),              x_("LFPLUG"),        LFPLUG},
113 	{x_("overglass"),         x_("LFOVERGLASS"),   LFOVERGLASS},
114 	{x_("resistor"),          x_("LFRESISTOR"),    LFRESISTOR},
115 	{x_("capacitor"),         x_("LFCAP"),         LFCAP},
116 	{x_("transistor"),        x_("LFTRANSISTOR"),  LFTRANSISTOR},
117 	{x_("emitter"),           x_("LFEMITTER"),     LFEMITTER},
118 	{x_("base"),              x_("LFBASE"),        LFBASE},
119 	{x_("collector"),         x_("LFCOLLECTOR"),   LFCOLLECTOR},
120 	{x_("substrate"),         x_("LFSUBSTRATE"),   LFSUBSTRATE},
121 	{x_("well"),              x_("LFWELL"),        LFWELL},
122 	{x_("guard"),             x_("LFGUARD"),       LFGUARD},
123 	{x_("isolation"),         x_("LFISOLATION"),   LFISOLATION},
124 	{x_("bus"),               x_("LFBUS"),         LFBUS},
125 	{x_("art"),               x_("LFART"),         LFART},
126 	{x_("control"),           x_("LFCONTROL"),     LFCONTROL},
127 
128 	{x_("p-type"),            x_("LFPTYPE"),       LFPTYPE},
129 	{x_("n-type"),            x_("LFNTYPE"),       LFNTYPE},
130 	{x_("depletion"),         x_("LFDEPLETION"),   LFDEPLETION},
131 	{x_("enhancement"),       x_("LFENHANCEMENT"), LFENHANCEMENT},
132 	{x_("light"),             x_("LFLIGHT"),       LFLIGHT},
133 	{x_("heavy"),             x_("LFHEAVY"),       LFHEAVY},
134 	{x_("pseudo"),            x_("LFPSEUDO"),      LFPSEUDO},
135 	{x_("nonelectrical"),     x_("LFNONELEC"),     LFNONELEC},
136 	{x_("connects-metal"),    x_("LFCONMETAL"),    LFCONMETAL},
137 	{x_("connects-poly"),     x_("LFCONPOLY"),     LFCONPOLY},
138 	{x_("connects-diff"),     x_("LFCONDIFF"),     LFCONDIFF},
139 	{x_("inside-transistor"), x_("LFINTRANS"),     LFINTRANS},
140 	{NULL, NULL, 0}
141 };
142 
143 /* these must correspond to the layer functions in "efunction.h" */
144 LIST us_tecarc_functions[] =
145 {
146 	{x_("unknown"),             x_("APUNKNOWN"),  APUNKNOWN},
147 	{x_("metal-1"),             x_("APMETAL1"),   APMETAL1},
148 	{x_("metal-2"),             x_("APMETAL2"),   APMETAL2},
149 	{x_("metal-3"),             x_("APMETAL3"),   APMETAL3},
150 	{x_("metal-4"),             x_("APMETAL4"),   APMETAL4},
151 	{x_("metal-5"),             x_("APMETAL5"),   APMETAL5},
152 	{x_("metal-6"),             x_("APMETAL6"),   APMETAL6},
153 	{x_("metal-7"),             x_("APMETAL7"),   APMETAL7},
154 	{x_("metal-8"),             x_("APMETAL8"),   APMETAL8},
155 	{x_("metal-9"),             x_("APMETAL9"),   APMETAL9},
156 	{x_("metal-10"),            x_("APMETAL10"),  APMETAL10},
157 	{x_("metal-11"),            x_("APMETAL11"),  APMETAL11},
158 	{x_("metal-12"),            x_("APMETAL12"),  APMETAL12},
159 	{x_("polysilicon-1"),       x_("APPOLY1"),    APPOLY1},
160 	{x_("polysilicon-2"),       x_("APPOLY2"),    APPOLY2},
161 	{x_("polysilicon-3"),       x_("APPOLY3"),    APPOLY3},
162 	{x_("diffusion"),           x_("APDIFF"),     APDIFF},
163 	{x_("p-Diffusion"),         x_("APDIFFP"),    APDIFFP},
164 	{x_("n-Diffusion"),         x_("APDIFFN"),    APDIFFN},
165 	{x_("substrate-Diffusion"), x_("APDIFFS"),    APDIFFS},
166 	{x_("well-Diffusion"),      x_("APDIFFW"),    APDIFFW},
167 	{x_("bus"),                 x_("APBUS"),      APBUS},
168 	{x_("unrouted"),            x_("APUNROUTED"), APUNROUTED},
169 	{x_("nonelectrical"),       x_("APNONELEC"),  APNONELEC},
170 	{NULL, NULL, 0}
171 };
172 
173 static GRAPHICS us_edtechigh = {LAYERH, HIGHLIT, SOLIDC, SOLIDC,
174 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
175 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
176 
177 /* prototypes for local routines */
178 static void       us_teceditdrc(void);
179 static void       us_teceditcolormap(void);
180 static void       us_teceditcreat(INTBIG, CHAR*[]);
181 static void       us_teceditidentify(BOOLEAN);
182 static void       us_teceditinquire(void);
183 static void       us_teceditmodobject(INTBIG, CHAR*[]);
184 static void       us_tecedlayer3dheight(NODEINST*, INTBIG, CHAR*[]);
185 static void       us_tecedlayer3dthick(NODEINST*, INTBIG, CHAR*[]);
186 static void       us_tecedlayerprintcol(NODEINST*, INTBIG, CHAR*[]);
187 static void       us_tecedlayercolor(NODEINST*, INTBIG, CHAR*[]);
188 static void       us_tecedlayerdrcminwid(NODEINST*, INTBIG, CHAR*[]);
189 static void       us_tecedlayerstyle(NODEINST*, INTBIG, CHAR*[]);
190 static void       us_tecedlayercif(NODEINST*, INTBIG, CHAR*[]);
191 static void       us_tecedlayerdxf(NODEINST*, INTBIG, CHAR*[]);
192 static void       us_tecedlayergds(NODEINST*, INTBIG, CHAR*[]);
193 static void       us_tecedlayerspires(NODEINST*, INTBIG, CHAR*[]);
194 static void       us_tecedlayerspicap(NODEINST*, INTBIG, CHAR*[]);
195 static void       us_tecedlayerspiecap(NODEINST*, INTBIG, CHAR*[]);
196 static void       us_tecedlayerfunction(NODEINST*, INTBIG, CHAR*[]);
197 static void       us_tecedlayerletters(NODEINST*, INTBIG, CHAR*[]);
198 static void       us_tecedlayerpatterncontrol(NODEINST*, INTBIG, CHAR*[]);
199 static void       us_tecedlayerpattern(NODEINST*);
200 static void       us_tecedlayertype(NODEINST*, INTBIG, CHAR*[]);
201 static void       us_tecedmodport(NODEINST*, INTBIG, CHAR*[]);
202 static void       us_tecedarcfunction(NODEINST*, INTBIG, CHAR*[]);
203 static void       us_tecedarcfixang(NODEINST*, INTBIG, CHAR*[]);
204 static void       us_tecedarcwipes(NODEINST*, INTBIG, CHAR*[]);
205 static void       us_tecedarcnoextend(NODEINST*, INTBIG, CHAR*[]);
206 static void       us_tecedarcinc(NODEINST*, INTBIG, CHAR*[]);
207 static void       us_tecednodefunction(NODEINST*, INTBIG, CHAR*[]);
208 static void       us_tecednodeserpentine(NODEINST*, INTBIG, CHAR*[]);
209 static void       us_tecednodesquare(NODEINST*, INTBIG, CHAR*[]);
210 static void       us_tecednodewipes(NODEINST*, INTBIG, CHAR*[]);
211 static void       us_tecednodelockable(NODEINST*, INTBIG, CHAR*[]);
212 static void       us_tecednodemulticut(NODEINST*, INTBIG, CHAR*[]);
213 static void       us_tecedinfolambda(NODEINST*, INTBIG, CHAR*[]);
214 static void       us_tecedinfodescript(NODEINST*, INTBIG, CHAR*[]);
215 static void       us_tecedsetnode(NODEINST*, CHAR*);
216 static NODEPROTO *us_tecedentercell(CHAR*);
217 static void       us_tecedredolayergraphics(NODEPROTO*);
218 static void       us_tecedloadlibmap(LIBRARY*);
219 static INTBIG     us_teceditparsefun(CHAR*);
220 static BOOLEAN    us_tecedgetdrc(CHAR *str, BOOLEAN *connected, BOOLEAN *wide, BOOLEAN *multi,
221 					INTBIG *widrule, BOOLEAN *edge, INTBIG *amt, INTBIG *layer1, INTBIG *layer2,
222 					CHAR **rule, INTBIG maxlayers, CHAR **layernames);
223 static void       us_tecedrenamesequence(CHAR *varname, CHAR *oldname, CHAR *newname);
224 static void       us_reorderprimdlog(CHAR *type, CHAR *prefix, CHAR *varname);
225 static NODEINST  *us_tecedlayersetpattern(NODEINST *ni, INTSML color);
226 static INTSML     us_tecedlayergetpattern(NODEINST *ni);
227 static void       us_teceditsetlayerpattern(NODEPROTO *np, GRAPHICS *desc);
228 
229 /*
230  * the entry routine for all technology editing
231  */
us_tecedentry(INTBIG count,CHAR * par[])232 void us_tecedentry(INTBIG count, CHAR *par[])
233 {
234 	REGISTER TECHNOLOGY *tech;
235 	REGISTER LIBRARY *lib;
236 	LIBRARY **dependentlibs;
237 	NODEPROTO **sequence;
238 	REGISTER CHAR *pp, **dependentlist;
239 	CHAR *cellname, *newpar[2];
240 	UINTSML stip[16];
241 	REGISTER INTBIG i, l;
242 	REGISTER INTBIG dependentlibcount;
243 	REGISTER NODEPROTO *np;
244 	REGISTER VARIABLE *var;
245 	REGISTER void *infstr;
246 
247 	if (count == 0)
248 	{
249 		ttyputusage(x_("technology edit OPTION"));
250 		return;
251 	}
252 
253 	l = estrlen(pp = par[0]);
254 	if (namesamen(pp, x_("library-to-tech-and-c"), l) == 0 && l >= 21)
255 	{
256 		if (count <= 1) pp = 0; else
257 			pp = par[1];
258 		us_tecfromlibinit(el_curlib, pp, 1);
259 		return;
260 	}
261 	if (namesamen(pp, x_("library-to-tech-and-java"), l) == 0 && l >= 21)
262 	{
263 		if (count <= 1) pp = 0; else
264 			pp = par[1];
265 		us_tecfromlibinit(el_curlib, pp, -1);
266 		return;
267 	}
268 	if (namesamen(pp, x_("library-to-tech"), l) == 0)
269 	{
270 		if (count <= 1) pp = 0; else
271 			pp = par[1];
272 		us_tecfromlibinit(el_curlib, pp, 0);
273 		return;
274 	}
275 	if (namesamen(pp, x_("tech-to-library"), l) == 0)
276 	{
277 		if (count == 1) tech = el_curtech; else
278 		{
279 			tech = gettechnology(par[1]);
280 			if (tech == NOTECHNOLOGY)
281 			{
282 				us_abortcommand(_("Technology '%s' unknown"), par[1]);
283 				return;
284 			}
285 		}
286 		if ((tech->userbits&NONSTANDARD) != 0)
287 		{
288 			us_abortcommand(_("Cannot convert technology '%s', it is nonstandard"), tech->techname);
289 			return;
290 		}
291 
292 		/* see if there is already such a library */
293 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
294 			if (namesame(lib->libname, tech->techname) == 0) break;
295 		if (lib != NOLIBRARY)
296 			ttyputmsg(_("Already a library called %s, using that"), lib->libname); else
297 				lib = us_tecedmakelibfromtech(tech);
298 		if (lib != NOLIBRARY)
299 		{
300 			newpar[0] = x_("use");
301 			newpar[1] = lib->libname;
302 			us_library(2, newpar);
303 			us_tecedloadlibmap(lib);
304 		}
305 		return;
306 	}
307 	if (namesamen(pp, x_("reorder-arcs"), l) == 0 && l >= 9)
308 	{
309 		us_reorderprimdlog(_("Arcs"), x_("arc-"), x_("EDTEC_arcsequence"));
310 		return;
311 	}
312 	if (namesamen(pp, x_("reorder-nodes"), l) == 0 && l >= 9)
313 	{
314 		us_reorderprimdlog(_("Nodes"), x_("node-"), x_("EDTEC_nodesequence"));
315 		return;
316 	}
317 	if (namesamen(pp, x_("reorder-layers"), l) == 0 && l >= 9)
318 	{
319 		us_reorderprimdlog(_("Layers"), x_("layer-"), x_("EDTEC_layersequence"));
320 		return;
321 	}
322 	if (namesamen(pp, x_("inquire-layer"), l) == 0 && l >= 2)
323 	{
324 		us_teceditinquire();
325 		return;
326 	}
327 	if (namesamen(pp, x_("place-layer"), l) == 0)
328 	{
329 		if (count < 2)
330 		{
331 			ttyputusage(x_("technology edit place-layer SHAPE"));
332 			return;
333 		}
334 
335 		us_teceditcreat(count-1, &par[1]);
336 		return;
337 	}
338 	if (namesamen(pp, x_("change"), l) == 0 && l >= 2)
339 	{
340 		/* in outline edit, create a point */
341 		if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
342 		{
343 			newpar[0] = x_("trace");
344 			newpar[1] = x_("add-point");
345 			us_node(2, newpar);
346 			return;
347 		}
348 
349 		us_teceditmodobject(count-1, &par[1]);
350 		return;
351 	}
352 	if (namesamen(pp, x_("edit-node"), l) == 0 && l >= 6)
353 	{
354 		if (count < 2)
355 		{
356 			ttyputusage(x_("technology edit edit-node NODENAME"));
357 			return;
358 		}
359 		infstr = initinfstr();
360 		addstringtoinfstr(infstr, x_("node-"));
361 		addstringtoinfstr(infstr, par[1]);
362 		(void)allocstring(&cellname, returninfstr(infstr), el_tempcluster);
363 
364 		/* first make sure all fields exist */
365 		np = getnodeproto(cellname);
366 		if (np != NONODEPROTO)
367 		{
368 			us_tecedmakenode(np, NPUNKNOWN, FALSE, FALSE, FALSE, FALSE, 0);
369 			(*el_curconstraint->solve)(np);
370 		}
371 
372 		np = us_tecedentercell(cellname);
373 		efree(cellname);
374 		if (np == NONODEPROTO) return;
375 		us_tecedmakenode(np, NPUNKNOWN, FALSE, FALSE, FALSE, FALSE, 0);
376 		(*el_curconstraint->solve)(np);
377 		np->userbits |= TECEDITCELL;
378 		(void)us_tecedentercell(describenodeproto(np));
379 		return;
380 	}
381 	if (namesamen(pp, x_("edit-arc"), l) == 0 && l >= 6)
382 	{
383 		if (count < 2)
384 		{
385 			ttyputusage(x_("technology edit edit-arc ARCNAME"));
386 			return;
387 		}
388 		infstr = initinfstr();
389 		addstringtoinfstr(infstr, x_("arc-"));
390 		addstringtoinfstr(infstr, par[1]);
391 		(void)allocstring(&cellname, returninfstr(infstr), el_tempcluster);
392 		np = us_tecedentercell(cellname);
393 		efree(cellname);
394 		if (np == NONODEPROTO) return;
395 		us_tecedmakearc(np, APUNKNOWN, 1, 1, 0, 90);
396 		(*el_curconstraint->solve)(np);
397 		np->userbits |= TECEDITCELL;
398 		(void)us_tecedentercell(describenodeproto(np));
399 		return;
400 	}
401 	if (namesamen(pp, x_("edit-layer"), l) == 0 && l >= 6)
402 	{
403 		if (count < 2)
404 		{
405 			ttyputusage(x_("technology edit edit-layer LAYERNAME"));
406 			return;
407 		}
408 		infstr = initinfstr();
409 		addstringtoinfstr(infstr, x_("layer-"));
410 		addstringtoinfstr(infstr, par[1]);
411 		(void)allocstring(&cellname, returninfstr(infstr), el_tempcluster);
412 
413 		/* first make sure all fields exist */
414 		for(i=0; i<16; i++) stip[i] = 0;
415 		np = getnodeproto(cellname);
416 		if (np != NONODEPROTO)
417 		{
418 			us_tecedmakelayer(np, COLORT1, stip, SOLIDC, x_("XX"), LFUNKNOWN, x_("x"), x_(""),
419 				x_(""), 0.0, 0.0, 0.0, 0, 0, 0);
420 			(*el_curconstraint->solve)(np);
421 		}
422 
423 		np = us_tecedentercell(cellname);
424 		efree(cellname);
425 		if (np == NONODEPROTO) return;
426 		us_tecedmakelayer(np, COLORT1, stip, SOLIDC, x_("XX"), LFUNKNOWN, x_("x"), x_(""),
427 			x_(""), 0.0, 0.0, 0.0, 0, 0, 0);
428 		(*el_curconstraint->solve)(np);
429 		np->userbits |= TECEDITCELL;
430 		(void)us_tecedentercell(describenodeproto(np));
431 		return;
432 	}
433 	if (namesamen(pp, x_("edit-subsequent"), l) == 0 && l >= 6)
434 	{
435 		np = us_needcell();
436 		if (np == NONODEPROTO) return;
437 		if (namesamen(np->protoname, x_("node-"), 5) == 0)
438 		{
439 			dependentlibcount = us_teceditgetdependents(el_curlib, &dependentlibs);
440 			i = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("node-"),
441 				x_("EDTEC_nodesequence"), &sequence);
442 			if (i == 0) return;
443 			for(l=0; l<i; l++) if (sequence[l] == np)
444 			{
445 				if (l == i-1) np = sequence[0]; else np = sequence[l+1];
446 				(void)us_tecedentercell(describenodeproto(np));
447 				break;
448 			}
449 			efree((CHAR *)sequence);
450 			return;
451 		}
452 		if (namesamen(np->protoname, x_("arc-"), 4) == 0)
453 		{
454 			dependentlibcount = us_teceditgetdependents(el_curlib, &dependentlibs);
455 			i = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("arc-"),
456 				x_("EDTEC_arcsequence"), &sequence);
457 			if (i == 0) return;
458 			for(l=0; l<i; l++) if (sequence[l] == np)
459 			{
460 				if (l == i-1) np = sequence[0]; else np = sequence[l+1];
461 				(void)us_tecedentercell(describenodeproto(np));
462 				break;
463 			}
464 			efree((CHAR *)sequence);
465 			return;
466 		}
467 		if (namesamen(np->protoname, x_("layer-"), 6) == 0)
468 		{
469 			dependentlibcount = us_teceditgetdependents(el_curlib, &dependentlibs);
470 			i = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("layer-"),
471 				x_("EDTEC_layersequence"), &sequence);
472 			if (i == 0) return;
473 			for(l=0; l<i; l++) if (sequence[l] == np)
474 			{
475 				if (l == i-1) np = sequence[0]; else np = sequence[l+1];
476 				(void)us_tecedentercell(describenodeproto(np));
477 				break;
478 			}
479 			efree((CHAR *)sequence);
480 			return;
481 		}
482 		ttyputerr(_("Must be editing a layer, node, or arc to advance to the next"));
483 		return;
484 	}
485 	if (namesamen(pp, x_("edit-colors"), l) == 0 && l >= 6)
486 	{
487 		us_teceditcolormap();
488 		return;
489 	}
490 	if (namesamen(pp, x_("edit-design-rules"), l) == 0 && l >= 6)
491 	{
492 		us_teceditdrc();
493 		return;
494 	}
495 	if (namesamen(pp, x_("edit-misc-information"), l) == 0 && l >= 6)
496 	{
497 		/* first make sure all fields exist */
498 		np = getnodeproto(x_("factors"));
499 		if (np != NONODEPROTO)
500 		{
501 			us_tecedmakeinfo(np, 2000, el_curlib->libname);
502 			(*el_curconstraint->solve)(np);
503 		}
504 
505 		/* now edit the cell */
506 		np = us_tecedentercell(x_("factors"));
507 		if (np == NONODEPROTO) return;
508 		us_tecedmakeinfo(np, 2000, el_curlib->libname);
509 		(*el_curconstraint->solve)(np);
510 		(void)us_tecedentercell(describenodeproto(np));
511 		return;
512 	}
513 	if (namesamen(pp, x_("identify-layers"), l) == 0 && l >= 10)
514 	{
515 		us_teceditidentify(FALSE);
516 		return;
517 	}
518 	if (namesamen(pp, x_("identify-ports"), l) == 0 && l >= 10)
519 	{
520 		us_teceditidentify(TRUE);
521 		return;
522 	}
523 	if (namesamen(pp, x_("dependent-libraries"), l) == 0 && l >= 2)
524 	{
525 		if (count < 2)
526 		{
527 			/* display dependent library names */
528 			var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_dependent_libraries"));
529 			if (var == NOVARIABLE) ttyputmsg(_("There are no dependent libraries")); else
530 			{
531 				i = getlength(var);
532 				ttyputmsg(_("%ld dependent %s:"), i, makeplural(x_("library"), i));
533 				for(l=0; l<i; l++)
534 				{
535 					pp = ((CHAR **)var->addr)[l];
536 					lib = getlibrary(pp);
537 					ttyputmsg(x_("    %s%s"), pp, (lib == NOLIBRARY ? _(" (not read in)") : x_("")));
538 				}
539 			}
540 			return;
541 		}
542 
543 		/* clear list if just "-" is given */
544 		if (count == 2 && estrcmp(par[1], x_("-")) == 0)
545 		{
546 			var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_dependent_libraries"));
547 			if (var != NOVARIABLE)
548 				(void)delval((INTBIG)el_curlib, VLIBRARY, x_("EDTEC_dependent_libraries"));
549 			return;
550 		}
551 
552 		/* create a list */
553 		dependentlist = (CHAR **)emalloc((count-1) * (sizeof (CHAR *)), el_tempcluster);
554 		if (dependentlist == 0) return;
555 		for(i=1; i<count; i++) dependentlist[i-1] = par[i];
556 		(void)setval((INTBIG)el_curlib, VLIBRARY, x_("EDTEC_dependent_libraries"), (INTBIG)dependentlist,
557 			VSTRING|VISARRAY|((count-1)<<VLENGTHSH));
558 		efree((CHAR *)dependentlist);
559 		return;
560 	}
561 	if (namesamen(pp, x_("compact-current-cell"), l) == 0 && l >= 2)
562 	{
563 		if (el_curwindowpart == NOWINDOWPART) np = NONODEPROTO; else
564 			np = el_curwindowpart->curnodeproto;
565 		if (np != NONODEPROTO) us_tecedcompact(np); else
566 			ttyputmsg(_("No current cell to compact"));
567 		return;
568 	}
569 	ttyputbadusage(x_("technology edit"));
570 }
571 
572 /*
573  * Routine to compact the current technology-edit cell
574  */
us_tecedcompact(NODEPROTO * cell)575 void us_tecedcompact(NODEPROTO *cell)
576 {
577 	REGISTER EXAMPLE *nelist, *ne;
578 	REGISTER SAMPLE *ns;
579 	REGISTER BOOLEAN first;
580 	REGISTER INTBIG i, numexamples, xoff, yoff, examplenum, leftheight, height,
581 		lx, hx, ly, hy, topy, separation;
582 	REGISTER NODEINST *ni;
583 
584 	if (namesame(cell->protoname, x_("factors")) == 0)
585 	{
586 		/* save highlighting */
587 		us_pushhighlight();
588 		us_clearhighlightcount();
589 
590 		/* move the option text */
591 		us_tecedfindspecialtext(cell, us_tecedmisctexttable);
592 		for(i=0; us_tecedmisctexttable[i].funct != 0; i++)
593 		{
594 			ni = us_tecedmisctexttable[i].ni;
595 			if (ni == NONODEINST) continue;
596 			xoff = us_tecedmisctexttable[i].x - (ni->lowx + ni->highx) / 2;
597 			yoff = us_tecedmisctexttable[i].y - (ni->lowy + ni->highy) / 2;
598 			if (xoff == 0 && yoff == 0) continue;
599 			startobjectchange((INTBIG)ni, VNODEINST);
600 			modifynodeinst(ni, xoff, yoff, xoff, yoff, 0, 0);
601 			endobjectchange((INTBIG)ni, VNODEINST);
602 		}
603 		us_pophighlight(FALSE);
604 		return;
605 	}
606 	if (namesamen(cell->protoname, x_("layer-"), 6) == 0)
607 	{
608 		ttyputmsg("Cannot compact technology-edit layer cells");
609 		return;
610 	}
611 	if (namesamen(cell->protoname, x_("arc-"), 4) == 0)
612 	{
613 		/* save highlighting */
614 		us_pushhighlight();
615 		us_clearhighlightcount();
616 
617 		/* move the option text */
618 		us_tecedfindspecialtext(cell, us_tecedarctexttable);
619 		for(i=0; us_tecedarctexttable[i].funct != 0; i++)
620 		{
621 			ni = us_tecedarctexttable[i].ni;
622 			if (ni == NONODEINST) continue;
623 			xoff = us_tecedarctexttable[i].x - (ni->lowx + ni->highx) / 2;
624 			yoff = us_tecedarctexttable[i].y - (ni->lowy + ni->highy) / 2;
625 			if (xoff == 0 && yoff == 0) continue;
626 			startobjectchange((INTBIG)ni, VNODEINST);
627 			modifynodeinst(ni, xoff, yoff, xoff, yoff, 0, 0);
628 			endobjectchange((INTBIG)ni, VNODEINST);
629 		}
630 
631 		/* compute bounds of arc contents */
632 		first = TRUE;
633 		for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
634 		{
635 			/* ignore the special text nodes */
636 			for(i=0; us_tecedarctexttable[i].funct != 0; i++)
637 				if (us_tecedarctexttable[i].ni == ni) break;
638 			if (us_tecedarctexttable[i].funct != 0) continue;
639 
640 			if (first)
641 			{
642 				first = FALSE;
643 				lx = ni->lowx;   hx = ni->highx;
644 				ly = ni->lowy;   hy = ni->highy;
645 			} else
646 			{
647 				if (ni->lowx < lx) lx = ni->lowx;
648 				if (ni->highx > hx) hx = ni->highx;
649 				if (ni->lowy < ly) ly = ni->lowy;
650 				if (ni->highy > hy) hy = ni->highy;
651 			}
652 		}
653 
654 		/* now rearrange the geometry */
655 		if (!first)
656 		{
657 			xoff = -(lx + hx) / 2;
658 			yoff = -hy;
659 			if (xoff != 0 || yoff != 0)
660 			{
661 				for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
662 				{
663 					/* ignore the special text nodes */
664 					for(i=0; us_tecedarctexttable[i].funct != 0; i++)
665 						if (us_tecedarctexttable[i].ni == ni) break;
666 					if (us_tecedarctexttable[i].funct != 0) continue;
667 
668 					startobjectchange((INTBIG)ni, VNODEINST);
669 					modifynodeinst(ni, xoff, yoff, xoff, yoff, 0, 0);
670 					endobjectchange((INTBIG)ni, VNODEINST);
671 				}
672 			}
673 		}
674 		us_pophighlight(FALSE);
675 		return;
676 	}
677 	if (namesamen(cell->protoname, x_("node-"), 5) == 0)
678 	{
679 		/* save highlighting */
680 		us_pushhighlight();
681 		us_clearhighlightcount();
682 
683 		/* move the option text */
684 		us_tecedfindspecialtext(cell, us_tecednodetexttable);
685 		for(i=0; us_tecednodetexttable[i].funct != 0; i++)
686 		{
687 			ni = us_tecednodetexttable[i].ni;
688 			if (ni == NONODEINST) continue;
689 			xoff = us_tecednodetexttable[i].x - (ni->lowx + ni->highx) / 2;
690 			yoff = us_tecednodetexttable[i].y - (ni->lowy + ni->highy) / 2;
691 			if (xoff == 0 && yoff == 0) continue;
692 			startobjectchange((INTBIG)ni, VNODEINST);
693 			modifynodeinst(ni, xoff, yoff, xoff, yoff, 0, 0);
694 			endobjectchange((INTBIG)ni, VNODEINST);
695 		}
696 
697 		/* move the examples */
698 		nelist = us_tecedgetexamples(cell, TRUE);
699 		if (nelist == NOEXAMPLE) return;
700 		numexamples = 0;
701 		for(ne = nelist; ne != NOEXAMPLE; ne = ne->nextexample) numexamples++;
702 		examplenum = 0;
703 		topy = 0;
704 		separation = mini(nelist->hx - nelist->lx, nelist->hy - nelist->ly);
705 		for(ne = nelist; ne != NOEXAMPLE; ne = ne->nextexample)
706 		{
707 			/* handle left or right side */
708 			yoff = topy - ne->hy;
709 			if ((examplenum&1) == 0)
710 			{
711 				/* do left side */
712 				if (examplenum == numexamples-1)
713 				{
714 					/* last one is centered */
715 					xoff = -(ne->lx + ne->hx) / 2;
716 				} else
717 				{
718 					xoff = -ne->hx - separation/2;
719 				}
720 				leftheight = ne->hy - ne->ly;
721 			} else
722 			{
723 				/* do right side */
724 				xoff = -ne->lx + separation/2;
725 				height = ne->hy - ne->ly;
726 				if (leftheight > height) height = leftheight;
727 				topy -= height + separation;
728 			}
729 			examplenum++;
730 
731 			/* adjust every node in the example */
732 			if (xoff == 0 && yoff == 0) continue;
733 			for(ns = ne->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
734 			{
735 				ni = ns->node;
736 				startobjectchange((INTBIG)ni, VNODEINST);
737 				modifynodeinst(ni, xoff, yoff, xoff, yoff, 0, 0);
738 				endobjectchange((INTBIG)ni, VNODEINST);
739 			}
740 		}
741 		us_tecedfreeexamples(nelist);
742 		us_pophighlight(FALSE);
743 		return;
744 	}
745 	ttyputmsg(_("Cannot compact technology-edit cell %s: unknown type"),
746 		describenodeproto(cell));
747 }
748 
749 /*
750  * Routine for editing the DRC tables.
751  */
us_teceditdrc(void)752 void us_teceditdrc(void)
753 {
754 	REGISTER INTBIG i, changed, nodecount;
755 	NODEPROTO **nodesequence;
756 	LIBRARY *liblist[1];
757 	REGISTER VARIABLE *var;
758 	REGISTER DRCRULES *rules;
759 
760 	/* get the current list of layer and node names */
761 	us_tecedgetlayernamelist();
762 	liblist[0] = el_curlib;
763 	nodecount = us_teceditfindsequence(liblist, 1, x_("node-"), x_("EDTEC_nodesequence"), &nodesequence);
764 
765 	/* create a RULES structure */
766 	rules = dr_allocaterules(us_teceddrclayers, nodecount, x_("EDITED TECHNOLOGY"));
767 	if (rules == NODRCRULES) return;
768 	for(i=0; i<us_teceddrclayers; i++)
769 		(void)allocstring(&rules->layernames[i], us_teceddrclayernames[i], el_tempcluster);
770 	for(i=0; i<nodecount; i++)
771 		(void)allocstring(&rules->nodenames[i], &nodesequence[i]->protoname[5], el_tempcluster);
772 	if (nodecount > 0) efree((CHAR *)nodesequence);
773 
774 	/* get the text-list of design rules and convert them into arrays */
775 	var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_DRC"));
776 	us_teceditgetdrcarrays(var, rules);
777 
778 	/* edit the design-rule arrays */
779 	changed = dr_rulesdlog(NOTECHNOLOGY, rules);
780 
781 	/* if changes were made, convert the arrays back into a text-list */
782 	if (changed != 0)
783 	{
784 		us_tecedloaddrcmessage(rules, el_curlib);
785 	}
786 
787 	/* free the arrays */
788 	dr_freerules(rules);
789 }
790 
791 /*
792  * Routine to update tables to reflect that cell "oldname" is now called "newname".
793  * If "newname" is not valid, any rule that refers to "oldname" is removed.
794  *
795  */
us_tecedrenamecell(CHAR * oldname,CHAR * newname)796 void us_tecedrenamecell(CHAR *oldname, CHAR *newname)
797 {
798 	REGISTER VARIABLE *var;
799 	REGISTER INTBIG i, len;
800 	REGISTER BOOLEAN valid;
801 	INTBIG count;
802 	REGISTER CHAR *origstr, *firstkeyword, *keyword;
803 	CHAR *str, **strings;
804 	REGISTER void *infstr, *sa;
805 
806 	/* if this is a layer, rename the layer sequence array */
807 	if (namesamen(oldname, x_("layer-"), 6) == 0 && namesamen(newname, x_("layer-"), 6) == 0)
808 	{
809 		us_tecedrenamesequence(x_("EDTEC_layersequence"), &oldname[6], &newname[6]);
810 	}
811 
812 	/* if this is an arc, rename the arc sequence array */
813 	if (namesamen(oldname, x_("arc-"), 4) == 0 && namesamen(newname, x_("arc-"), 4) == 0)
814 	{
815 		us_tecedrenamesequence(x_("EDTEC_arcsequence"), &oldname[4], &newname[4]);
816 	}
817 
818 	/* if this is a node, rename the node sequence array */
819 	if (namesamen(oldname, x_("node-"), 5) == 0 && namesamen(newname, x_("node-"), 5) == 0)
820 	{
821 		us_tecedrenamesequence(x_("EDTEC_nodesequence"), &oldname[5], &newname[5]);
822 	}
823 
824 	/* see if there are design rules in the current library */
825 	var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_DRC"));
826 	if (var == NOVARIABLE) return;
827 
828 	/* examine the rules and convert the name */
829 	len = getlength(var);
830 	sa = newstringarray(us_tool->cluster);
831 	for(i=0; i<len; i++)
832 	{
833 		/* parse the DRC rule */
834 		str = ((CHAR **)var->addr)[i];
835 		origstr = str;
836 		firstkeyword = getkeyword(&str, x_(" "));
837 		if (firstkeyword == NOSTRING) return;
838 
839 		/* pass wide wire limitation through */
840 		if (*firstkeyword == 'l')
841 		{
842 			addtostringarray(sa, origstr);
843 			continue;
844 		}
845 
846 		/* rename nodes in the minimum node size rule */
847 		if (*firstkeyword == 'n')
848 		{
849 			if (namesamen(oldname, x_("node-"), 5) == 0 &&
850 				namesame(&oldname[5], &firstkeyword[1]) == 0)
851 			{
852 				/* substitute the new name */
853 				if (namesamen(newname, x_("node-"), 5) == 0)
854 				{
855 					infstr = initinfstr();
856 					addstringtoinfstr(infstr, x_("n"));
857 					addstringtoinfstr(infstr, &newname[5]);
858 					addstringtoinfstr(infstr, str);
859 					addtostringarray(sa, returninfstr(infstr));
860 				}
861 				continue;
862 			}
863 			addtostringarray(sa, origstr);
864 			continue;
865 		}
866 
867 		/* rename layers in the minimum layer size rule */
868 		if (*firstkeyword == 's')
869 		{
870 			valid = TRUE;
871 			infstr = initinfstr();
872 			formatinfstr(infstr, x_("%s "), firstkeyword);
873 			keyword = getkeyword(&str, x_(" "));
874 			if (keyword == NOSTRING) return;
875 			if (namesamen(oldname, x_("layer-"), 6) == 0 &&
876 				namesame(&oldname[6], keyword) == 0)
877 			{
878 				if (namesamen(newname, x_("layer-"), 6) != 0) valid = FALSE; else
879 					addstringtoinfstr(infstr, &newname[6]);
880 			} else
881 				addstringtoinfstr(infstr, keyword);
882 			addstringtoinfstr(infstr, str);
883 			str = returninfstr(infstr);
884 			if (valid) addtostringarray(sa, str);
885 			continue;
886 		}
887 
888 		/* layer width rule: substitute layer names */
889 		infstr = initinfstr();
890 		formatinfstr(infstr, x_("%s "), firstkeyword);
891 		valid = TRUE;
892 
893 		/* get the first layer name and convert it */
894 		keyword = getkeyword(&str, x_(" "));
895 		if (keyword == NOSTRING) return;
896 		if (namesamen(oldname, x_("layer-"), 6) == 0 &&
897 			namesame(&oldname[6], keyword) == 0)
898 		{
899 			/* substitute the new name */
900 			if (namesamen(newname, x_("layer-"), 6) != 0) valid = FALSE; else
901 				addstringtoinfstr(infstr, &newname[6]);
902 		} else
903 			addstringtoinfstr(infstr, keyword);
904 		addtoinfstr(infstr, ' ');
905 
906 		/* get the second layer name and convert it */
907 		keyword = getkeyword(&str, x_(" "));
908 		if (keyword == NOSTRING) return;
909 		if (namesamen(oldname, x_("layer-"), 6) == 0 &&
910 			namesame(&oldname[6], keyword) == 0)
911 		{
912 			/* substitute the new name */
913 			if (namesamen(newname, x_("layer-"), 6) != 0) valid = FALSE; else
914 				addstringtoinfstr(infstr, &newname[6]);
915 		} else
916 			addstringtoinfstr(infstr, keyword);
917 
918 		addstringtoinfstr(infstr, str);
919 		str = returninfstr(infstr);
920 		if (valid) addtostringarray(sa, str);
921 	}
922 	strings = getstringarray(sa, &count);
923 	setval((INTBIG)el_curlib, VLIBRARY, x_("EDTEC_DRC"), (INTBIG)strings,
924 		VSTRING|VISARRAY|(count<<VLENGTHSH));
925 	killstringarray(sa);
926 }
927 
928 /*
929  * Routine to rename the layer/arc/node sequence arrays to account for a name change.
930  * The sequence array is in variable "varname", and the item has changed from "oldname" to
931  * "newname".
932  */
us_tecedrenamesequence(CHAR * varname,CHAR * oldname,CHAR * newname)933 void us_tecedrenamesequence(CHAR *varname, CHAR *oldname, CHAR *newname)
934 {
935 	REGISTER VARIABLE *var;
936 	CHAR **strings;
937 	REGISTER INTBIG i, len;
938 	INTBIG count;
939 	void *sa;
940 
941 	var = getval((INTBIG)el_curlib, VLIBRARY, VSTRING|VISARRAY, varname);
942 	if (var == NOVARIABLE) return;
943 
944 	strings = (CHAR **)var->addr;
945 	len = getlength(var);
946 	sa = newstringarray(us_tool->cluster);
947 	for(i=0; i<len; i++)
948 	{
949 		if (namesame(strings[i], oldname) == 0)
950 			addtostringarray(sa, newname); else
951 				addtostringarray(sa, strings[i]);
952 	}
953 	strings = getstringarray(sa, &count);
954 	setval((INTBIG)el_curlib, VLIBRARY, varname, (INTBIG)strings,
955 		VSTRING|VISARRAY|(count<<VLENGTHSH));
956 	killstringarray(sa);
957 }
958 
us_tecedgetlayernamelist(void)959 void us_tecedgetlayernamelist(void)
960 {
961 	REGISTER INTBIG i, dependentlibcount;
962 	REGISTER NODEPROTO *np;
963 	NODEPROTO **sequence;
964 	LIBRARY **dependentlibs;
965 
966 	/* free any former layer name information */
967 	if (us_teceddrclayernames != 0)
968 	{
969 		for(i=0; i<us_teceddrclayers; i++) efree(us_teceddrclayernames[i]);
970 		efree((CHAR *)us_teceddrclayernames);
971 		us_teceddrclayernames = 0;
972 	}
973 
974 	dependentlibcount = us_teceditgetdependents(el_curlib, &dependentlibs);
975 	us_teceddrclayers = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("layer-"),
976 		x_("EDTEC_layersequence"), &sequence);
977 
978 	/* build and fill array of layers for DRC parsing */
979 	us_teceddrclayernames = (CHAR **)emalloc(us_teceddrclayers * (sizeof (CHAR *)), us_tool->cluster);
980 	if (us_teceddrclayernames == 0) return;
981 	for(i = 0; i<us_teceddrclayers; i++)
982 	{
983 		np = sequence[i];
984 		(void)allocstring(&us_teceddrclayernames[i], &np->protoname[6], us_tool->cluster);
985 	}
986 }
987 
988 /*
989  * Routine to create arrays describing the design rules in the variable "var" (which is
990  * from "EDTEC_DRC" on a library).  The arrays are stored in "rules".
991  */
us_teceditgetdrcarrays(VARIABLE * var,DRCRULES * rules)992 void us_teceditgetdrcarrays(VARIABLE *var, DRCRULES *rules)
993 {
994 	REGISTER INTBIG i, l;
995 	INTBIG amt;
996 	BOOLEAN connected, wide, multi, edge;
997 	INTBIG widrule, layer1, layer2, j;
998 	REGISTER CHAR *str, *pt;
999 	CHAR *rule;
1000 
1001 	/* get the design rules */
1002 	if (var == NOVARIABLE) return;
1003 
1004 	l = getlength(var);
1005 	for(i=0; i<l; i++)
1006 	{
1007 		/* parse the DRC rule */
1008 		str = ((CHAR **)var->addr)[i];
1009 		while (*str == ' ') str++;
1010 		if (*str == 0) continue;
1011 
1012 		/* special case for node minimum size rule */
1013 		if (*str == 'n')
1014 		{
1015 			str++;
1016 			for(pt = str; *pt != 0; pt++) if (*pt == ' ') break;
1017 			if (*pt == 0)
1018 			{
1019 				ttyputmsg(_("Bad node size rule (line %ld): %s"), i+1, str);
1020 				continue;
1021 			}
1022 			*pt = 0;
1023 			for(j=0; j<rules->numnodes; j++)
1024 				if (namesame(str, rules->nodenames[j]) == 0) break;
1025 			*pt = ' ';
1026 			if (j >= rules->numnodes)
1027 			{
1028 				ttyputmsg(_("Unknown node (line %ld): %s"), i+1, str);
1029 				continue;
1030 			}
1031 			while (*pt == ' ') pt++;
1032 			rules->minnodesize[j*2] = atofr(pt);
1033 			while (*pt != 0 && *pt != ' ') pt++;
1034 			while (*pt == ' ') pt++;
1035 			rules->minnodesize[j*2+1] = atofr(pt);
1036 			while (*pt != 0 && *pt != ' ') pt++;
1037 			while (*pt == ' ') pt++;
1038 			if (*pt != 0) reallocstring(&rules->minnodesizeR[j], pt, el_tempcluster);
1039 			continue;
1040 		}
1041 
1042 		/* parse the layer rule */
1043 		if (us_tecedgetdrc(str, &connected, &wide, &multi, &widrule, &edge,
1044 			&amt, &layer1, &layer2, &rule, rules->numlayers, rules->layernames))
1045 		{
1046 			ttyputmsg(_("DRC line %ld is: %s"), i+1, str);
1047 			continue;
1048 		}
1049 
1050 		/* set the layer spacing */
1051 		if (widrule == 1)
1052 		{
1053 			rules->minwidth[layer1] = amt;
1054 			if (*rule != 0)
1055 				(void)reallocstring(&rules->minwidthR[layer1], rule, el_tempcluster);
1056 		} else if (widrule == 2)
1057 		{
1058 			rules->widelimit = amt;
1059 		} else
1060 		{
1061 			if (layer1 > layer2) { j = layer1;  layer1 = layer2;  layer2 = j; }
1062 			j = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
1063 			j = layer2 + rules->numlayers * layer1 - j;
1064 			if (edge)
1065 			{
1066 				rules->edgelist[j] = amt;
1067 				if (*rule != 0)
1068 					(void)reallocstring(&rules->edgelistR[j], rule, el_tempcluster);
1069 			} else if (wide)
1070 			{
1071 				if (connected)
1072 				{
1073 					rules->conlistW[j] = amt;
1074 					if (*rule != 0)
1075 						(void)reallocstring(&rules->conlistWR[j], rule, el_tempcluster);
1076 				} else
1077 				{
1078 					rules->unconlistW[j] = amt;
1079 					if (*rule != 0)
1080 						(void)reallocstring(&rules->unconlistWR[j], rule, el_tempcluster);
1081 				}
1082 			} else if (multi)
1083 			{
1084 				if (connected)
1085 				{
1086 					rules->conlistM[j] = amt;
1087 					if (*rule != 0)
1088 						(void)reallocstring(&rules->conlistMR[j], rule, el_tempcluster);
1089 				} else
1090 				{
1091 					rules->unconlistM[j] = amt;
1092 					if (*rule != 0)
1093 						(void)reallocstring(&rules->unconlistMR[j], rule, el_tempcluster);
1094 				}
1095 			} else
1096 			{
1097 				if (connected)
1098 				{
1099 					rules->conlist[j] = amt;
1100 					if (*rule != 0)
1101 						(void)reallocstring(&rules->conlistR[j], rule, el_tempcluster);
1102 				} else
1103 				{
1104 					rules->unconlist[j] = amt;
1105 					if (*rule != 0)
1106 						(void)reallocstring(&rules->unconlistR[j], rule, el_tempcluster);
1107 				}
1108 			}
1109 		}
1110 	}
1111 }
1112 
1113 /*
1114  * routine to parse DRC line "str" and fill the factors "connected" (set nonzero
1115  * if rule is for connected layers), "amt" (rule distance), "layer1" and "layer2"
1116  * (the layers).  Presumes that there are "maxlayers" layer names in the
1117  * array "layernames".  Returns true on error.
1118  */
us_tecedgetdrc(CHAR * str,BOOLEAN * connected,BOOLEAN * wide,BOOLEAN * multi,INTBIG * widrule,BOOLEAN * edge,INTBIG * amt,INTBIG * layer1,INTBIG * layer2,CHAR ** rule,INTBIG maxlayers,CHAR ** layernames)1119 BOOLEAN us_tecedgetdrc(CHAR *str, BOOLEAN *connected, BOOLEAN *wide, BOOLEAN *multi, INTBIG *widrule,
1120 	BOOLEAN *edge, INTBIG *amt, INTBIG *layer1, INTBIG *layer2, CHAR **rule, INTBIG maxlayers,
1121 	CHAR **layernames)
1122 {
1123 	REGISTER CHAR *pt;
1124 	REGISTER INTBIG save;
1125 
1126 	*connected = *wide = *multi = *edge = FALSE;
1127 	for( ; *str != 0; str++)
1128 	{
1129 		if (tolower(*str) == 'c')
1130 		{
1131 			*connected = TRUE;
1132 			continue;
1133 		}
1134 		if (tolower(*str) == 'w')
1135 		{
1136 			*wide = TRUE;
1137 			continue;
1138 		}
1139 		if (tolower(*str) == 'm')
1140 		{
1141 			*multi = TRUE;
1142 			continue;
1143 		}
1144 		if (tolower(*str) == 'e')
1145 		{
1146 			*edge = TRUE;
1147 			continue;
1148 		}
1149 		break;
1150 	}
1151 	*widrule = 0;
1152 	if (tolower(*str) == 's')
1153 	{
1154 		*widrule = 1;
1155 		str++;
1156 	} else if (tolower(*str) == 'l')
1157 	{
1158 		*widrule = 2;
1159 		str++;
1160 	}
1161 
1162 	/* get the distance */
1163 	pt = str;
1164 	while (*pt != 0 && *pt != ' ' && *pt != '\t') pt++;
1165 	while (*pt == ' ' || *pt == '\t') pt++;
1166 	*amt = atofr(str);
1167 
1168 	/* get the first layer */
1169 	if (*widrule != 2)
1170 	{
1171 		str = pt;
1172 		if (*str == 0)
1173 		{
1174 			ttyputerr(_("Cannot find layer names on DRC line"));
1175 			return(TRUE);
1176 		}
1177 		while (*pt != 0 && *pt != ' ' && *pt != '\t') pt++;
1178 		if (*pt == 0)
1179 		{
1180 			ttyputerr(_("Cannot find layer name on DRC line"));
1181 			return(TRUE);
1182 		}
1183 		save = *pt;
1184 		*pt = 0;
1185 		for(*layer1 = 0; *layer1 < maxlayers; (*layer1)++)
1186 			if (namesame(str, layernames[*layer1]) == 0) break;
1187 		*pt++ = (CHAR)save;
1188 		if (*layer1 >= maxlayers)
1189 		{
1190 			ttyputerr(_("First DRC layer name unknown"));
1191 			return(TRUE);
1192 		}
1193 		while (*pt == ' ' || *pt == '\t') pt++;
1194 	}
1195 
1196 	/* get the second layer */
1197 	if (*widrule == 0)
1198 	{
1199 		str = pt;
1200 		while (*pt != 0 && *pt != ' ' && *pt != '\t') pt++;
1201 		save = *pt;
1202 		*pt = 0;
1203 		for(*layer2 = 0; *layer2 < maxlayers; (*layer2)++)
1204 			if (namesame(str, layernames[*layer2]) == 0) break;
1205 		*pt = (CHAR)save;
1206 		if (*layer2 >= maxlayers)
1207 		{
1208 			ttyputerr(_("Second DRC layer name unknown"));
1209 			return(TRUE);
1210 		}
1211 	}
1212 
1213 	while (*pt == ' ' || *pt == '\t') pt++;
1214 	*rule = pt;
1215 	return(FALSE);
1216 }
1217 
1218 /*
1219  * Helper routine to examine the arrays describing the design rules and create
1220  * the variable "EDTEC_DRC" on library "lib".
1221  */
us_tecedloaddrcmessage(DRCRULES * rules,LIBRARY * lib)1222 void us_tecedloaddrcmessage(DRCRULES *rules, LIBRARY *lib)
1223 {
1224 	REGISTER INTBIG drccount, drcindex, i, k, j;
1225 	REGISTER CHAR **drclist;
1226 	REGISTER void *infstr;
1227 
1228 	/* determine the number of lines in the text-version of the design rules */
1229 	drccount = 0;
1230 	for(i=0; i<rules->utsize; i++)
1231 	{
1232 		if (rules->conlist[i] >= 0) drccount++;
1233 		if (rules->unconlist[i] >= 0) drccount++;
1234 		if (rules->conlistW[i] >= 0) drccount++;
1235 		if (rules->unconlistW[i] >= 0) drccount++;
1236 		if (rules->conlistM[i] >= 0) drccount++;
1237 		if (rules->unconlistM[i] >= 0) drccount++;
1238 		if (rules->edgelist[i] >= 0) drccount++;
1239 	}
1240 	for(i=0; i<rules->numlayers; i++)
1241 	{
1242 		if (rules->minwidth[i] >= 0) drccount++;
1243 	}
1244 	for(i=0; i<rules->numnodes; i++)
1245 	{
1246 		if (rules->minnodesize[i*2] > 0 || rules->minnodesize[i*2+1] > 0) drccount++;
1247 	}
1248 
1249 	/* load the arrays */
1250 	if (drccount != 0)
1251 	{
1252 		drccount++;
1253 		drclist = (CHAR **)emalloc((drccount * (sizeof (CHAR *))), el_tempcluster);
1254 		if (drclist == 0) return;
1255 		drcindex = 0;
1256 
1257 		/* write the width limit */
1258 		infstr = initinfstr();
1259 		formatinfstr(infstr, x_("l%s"), frtoa(rules->widelimit));
1260 		(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1261 
1262 		/* write the minimum width for each layer */
1263 		for(i=0; i<rules->numlayers; i++)
1264 		{
1265 			if (rules->minwidth[i] >= 0)
1266 			{
1267 				infstr = initinfstr();
1268 				formatinfstr(infstr, x_("s%s %s %s"), frtoa(rules->minwidth[i]),
1269 					rules->layernames[i], rules->minwidthR[i]);
1270 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1271 			}
1272 		}
1273 
1274 		/* write the minimum size for each node */
1275 		for(i=0; i<rules->numnodes; i++)
1276 		{
1277 			if (rules->minnodesize[i*2] <= 0 && rules->minnodesize[i*2+1] <= 0) continue;
1278 			{
1279 				infstr = initinfstr();
1280 				formatinfstr(infstr, x_("n%s %s %s %s"), rules->nodenames[i],
1281 					frtoa(rules->minnodesize[i*2]), frtoa(rules->minnodesize[i*2+1]),
1282 					rules->minnodesizeR[i]);
1283 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1284 			}
1285 		}
1286 
1287 		/* now do the distance rules */
1288 		k = 0;
1289 		for(i=0; i<rules->numlayers; i++) for(j=i; j<rules->numlayers; j++)
1290 		{
1291 			if (rules->conlist[k] >= 0)
1292 			{
1293 				infstr = initinfstr();
1294 				formatinfstr(infstr, x_("c%s %s %s %s"), frtoa(rules->conlist[k]),
1295 					rules->layernames[i], rules->layernames[j],
1296 						rules->conlistR[k]);
1297 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1298 			}
1299 			if (rules->unconlist[k] >= 0)
1300 			{
1301 				infstr = initinfstr();
1302 				formatinfstr(infstr, x_("%s %s %s %s"), frtoa(rules->unconlist[k]),
1303 					rules->layernames[i], rules->layernames[j],
1304 						rules->unconlistR[k]);
1305 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1306 			}
1307 			if (rules->conlistW[k] >= 0)
1308 			{
1309 				infstr = initinfstr();
1310 				formatinfstr(infstr, x_("cw%s %s %s %s"), frtoa(rules->conlistW[k]),
1311 					rules->layernames[i], rules->layernames[j],
1312 						rules->conlistWR[k]);
1313 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1314 			}
1315 			if (rules->unconlistW[k] >= 0)
1316 			{
1317 				infstr = initinfstr();
1318 				formatinfstr(infstr, x_("w%s %s %s %s"), frtoa(rules->unconlistW[k]),
1319 					rules->layernames[i], rules->layernames[j],
1320 						rules->unconlistWR[k]);
1321 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1322 			}
1323 			if (rules->conlistM[k] >= 0)
1324 			{
1325 				infstr = initinfstr();
1326 				formatinfstr(infstr, x_("cm%s %s %s %s"), frtoa(rules->conlistM[k]),
1327 					rules->layernames[i], rules->layernames[j],
1328 						rules->conlistMR[k]);
1329 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1330 			}
1331 			if (rules->unconlistM[k] >= 0)
1332 			{
1333 				infstr = initinfstr();
1334 				formatinfstr(infstr, x_("m%s %s %s %s"), frtoa(rules->unconlistM[k]),
1335 					rules->layernames[i], rules->layernames[j],
1336 						rules->unconlistMR[k]);
1337 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1338 			}
1339 			if (rules->edgelist[k] >= 0)
1340 			{
1341 				infstr = initinfstr();
1342 				formatinfstr(infstr, x_("e%s %s %s %s"), frtoa(rules->edgelist[k]),
1343 					rules->layernames[i], rules->layernames[j],
1344 						rules->edgelistR[k]);
1345 				(void)allocstring(&drclist[drcindex++], returninfstr(infstr), el_tempcluster);
1346 			}
1347 			k++;
1348 		}
1349 
1350 		(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_DRC"), (INTBIG)drclist,
1351 			VSTRING|VISARRAY|(drccount<<VLENGTHSH));
1352 		for(i=0; i<drccount; i++) efree(drclist[i]);
1353 		efree((CHAR *)drclist);
1354 	} else
1355 	{
1356 		/* no rules: remove the variable */
1357 		if (getval((INTBIG)lib, VLIBRARY, VSTRING|VISARRAY, x_("EDTEC_DRC")) != NOVARIABLE)
1358 			(void)delval((INTBIG)lib, VLIBRARY, x_("EDTEC_DRC"));
1359 	}
1360 }
1361 
1362 /*
1363  * routine for manipulating color maps
1364  */
us_teceditcolormap(void)1365 void us_teceditcolormap(void)
1366 {
1367 	REGISTER INTBIG i, k, total, dependentlibcount, *printcolors;
1368 	INTBIG func, drcminwid, height3d, thick3d, printcol[5];
1369 	CHAR *layerlabel[5], *layerabbrev[5], *cif, *gds, *layerletters, *dxf, **layernames, line[50];
1370 	LIBRARY **dependentlibs;
1371 	GRAPHICS desc;
1372 	NODEPROTO **sequence;
1373 	REGISTER NODEINST *ni;
1374 	REGISTER NODEPROTO *np;
1375 	REGISTER VARIABLE *var;
1376 	float spires, spicap, spiecap;
1377 	REGISTER INTBIG *mapptr, *newmap;
1378 	REGISTER VARIABLE *varred, *vargreen, *varblue;
1379 
1380 	if (us_needwindow()) return;
1381 
1382 	/* load the color map of the technology */
1383 	us_tecedloadlibmap(el_curlib);
1384 
1385 	dependentlibcount = us_teceditgetdependents(el_curlib, &dependentlibs);
1386 	total = us_teceditfindsequence(dependentlibs, dependentlibcount, x_("layer-"),
1387 		x_("EDTEC_layersequence"), &sequence);
1388 	printcolors = (INTBIG *)emalloc(total*5*SIZEOFINTBIG, us_tool->cluster);
1389 	if (printcolors == 0) return;
1390 	layernames = (CHAR **)emalloc(total * (sizeof (CHAR *)), us_tool->cluster);
1391 	if (layernames == 0) return;
1392 
1393 	/* now fill in real layer names if known */
1394 	for(i=0; i<5; i++) layerlabel[i] = 0;
1395 	for(i=0; i<total; i++)
1396 	{
1397 		np = sequence[i];
1398 		cif = layerletters = gds = 0;
1399 		if (us_teceditgetlayerinfo(np, &desc, &cif, &func, &layerletters,
1400 			&dxf, &gds, &spires, &spicap, &spiecap, &drcminwid, &height3d,
1401 				&thick3d, printcol)) return;
1402 		for(k=0; k<5; k++) printcolors[i*5+k] = printcol[k];
1403 		layernames[i] = &np->protoname[6];
1404 		switch (desc.bits)
1405 		{
1406 			case LAYERT1: k = 0;   break;
1407 			case LAYERT2: k = 1;   break;
1408 			case LAYERT3: k = 2;   break;
1409 			case LAYERT4: k = 3;   break;
1410 			case LAYERT5: k = 4;   break;
1411 			default:      k = -1;  break;
1412 		}
1413 		if (k >= 0)
1414 		{
1415 			if (layerlabel[k] == 0)
1416 			{
1417 				layerlabel[k] = &np->protoname[6];
1418 				layerabbrev[k] = (CHAR *)emalloc(2 * SIZEOFCHAR, el_tempcluster);
1419 				layerabbrev[k][0] = *layerletters;
1420 				layerabbrev[k][1] = 0;
1421 			}
1422 		}
1423 		if (gds != 0) efree(gds);
1424 		if (cif != 0) efree(cif);
1425 		if (layerletters != 0) efree(layerletters);
1426 	}
1427 
1428 	/* set defaults */
1429 	if (layerlabel[0] == 0)
1430 	{
1431 		layerlabel[0] = _("Ovrlap 1");
1432 		(void)allocstring(&layerabbrev[0], x_("1"), el_tempcluster);
1433 	}
1434 	if (layerlabel[1] == 0)
1435 	{
1436 		layerlabel[1] = _("Ovrlap 2");
1437 		(void)allocstring(&layerabbrev[1], x_("2"), el_tempcluster);
1438 	}
1439 	if (layerlabel[2] == 0)
1440 	{
1441 		layerlabel[2] = _("Ovrlap 3");
1442 		(void)allocstring(&layerabbrev[2], x_("3"), el_tempcluster);
1443 	}
1444 	if (layerlabel[3] == 0)
1445 	{
1446 		layerlabel[3] = _("Ovrlap 4");
1447 		(void)allocstring(&layerabbrev[3], x_("4"), el_tempcluster);
1448 	}
1449 	if (layerlabel[4] == 0)
1450 	{
1451 		layerlabel[4] = _("Ovrlap 5");
1452 		(void)allocstring(&layerabbrev[4], x_("5"), el_tempcluster);
1453 	}
1454 
1455 	/* run the color mixing palette */
1456 	if (us_colormixdlog(layerlabel, total, layernames, printcolors))
1457 	{
1458 		/* update all of the layer cells */
1459 		for(i=0; i<total; i++)
1460 		{
1461 			np = sequence[i];
1462 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1463 			{
1464 				var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
1465 				if (var == NOVARIABLE) continue;
1466 				if (var->addr != LAYERPRINTCOL) continue;
1467 				(void)esnprintf(line, 50, x_("%s%ld,%ld,%ld, %ld,%s"), TECEDNODETEXTPRINTCOL,
1468 					printcolors[i*5], printcolors[i*5+1], printcolors[i*5+2],
1469 						printcolors[i*5+3], (printcolors[i*5+4]==0 ? x_("off") : x_("on")));
1470 				startobjectchange((INTBIG)ni, VNODEINST);
1471 				(void)setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)line,
1472 					VSTRING|VDISPLAY);
1473 				endobjectchange((INTBIG)ni, VNODEINST);
1474 			}
1475 		}
1476 	}
1477 	for(i=0; i<5; i++) efree(layerabbrev[i]);
1478 
1479 	/* save the map on the library */
1480 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
1481 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
1482 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
1483 	if (varred != NOVARIABLE && vargreen != NOVARIABLE && varblue != NOVARIABLE)
1484 	{
1485 		newmap = emalloc(256*3*SIZEOFINTBIG, el_tempcluster);
1486 		mapptr = newmap;
1487 		for(i=0; i<256; i++)
1488 		{
1489 			*mapptr++ = ((INTBIG *)varred->addr)[i];
1490 			*mapptr++ = ((INTBIG *)vargreen->addr)[i];
1491 			*mapptr++ = ((INTBIG *)varblue->addr)[i];
1492 		}
1493 		(void)setval((INTBIG)el_curlib, VLIBRARY, x_("EDTEC_colormap"), (INTBIG)newmap,
1494 			VINTEGER|VISARRAY|((256*3)<<VLENGTHSH));
1495 		efree((CHAR *)newmap);
1496 	}
1497 	efree((CHAR *)layernames);
1498 	efree((CHAR *)printcolors);
1499 }
1500 
1501 /*
1502  * routine for creating a new layer with shape "pp"
1503  */
us_teceditcreat(INTBIG count,CHAR * par[])1504 void us_teceditcreat(INTBIG count, CHAR *par[])
1505 {
1506 	REGISTER INTBIG l;
1507 	REGISTER CHAR *name, *pp;
1508 	CHAR *subpar[3];
1509 	REGISTER NODEINST *ni;
1510 	REGISTER NODEPROTO *np, *savenp, *cell;
1511 	HIGHLIGHT high;
1512 	REGISTER VARIABLE *var;
1513 
1514 	l = estrlen(pp = par[0]);
1515 	np = NONODEPROTO;
1516 	if (namesamen(pp, x_("port"), l) == 0 && l >= 1) np = gen_portprim;
1517 	if (namesamen(pp, x_("highlight"), l) == 0 && l >= 1) np = art_boxprim;
1518 	if (namesamen(pp, x_("rectangle-filled"), l) == 0 && l >= 11) np = art_filledboxprim;
1519 	if (namesamen(pp, x_("rectangle-outline"), l) == 0 && l >= 11) np = art_boxprim;
1520 	if (namesamen(pp, x_("rectangle-crossed"), l) == 0 && l >= 11) np = art_crossedboxprim;
1521 	if (namesamen(pp, x_("polygon-filled"), l) == 0 && l >= 9) np = art_filledpolygonprim;
1522 	if (namesamen(pp, x_("polygon-outline"), l) == 0 && l >= 9) np = art_closedpolygonprim;
1523 	if (namesamen(pp, x_("lines-solid"), l) == 0 && l >= 7) np = art_openedpolygonprim;
1524 	if (namesamen(pp, x_("lines-dotted"), l) == 0 && l >= 8) np = art_openeddottedpolygonprim;
1525 	if (namesamen(pp, x_("lines-dashed"), l) == 0 && l >= 8) np = art_openeddashedpolygonprim;
1526 	if (namesamen(pp, x_("lines-thicker"), l) == 0 && l >= 7) np = art_openedthickerpolygonprim;
1527 	if (namesamen(pp, x_("circle-outline"), l) == 0 && l >= 8) np = art_circleprim;
1528 	if (namesamen(pp, x_("circle-filled"), l) == 0 && l >= 8) np = art_filledcircleprim;
1529 	if (namesamen(pp, x_("circle-half"), l) == 0 && l >= 8) np = art_circleprim;
1530 	if (namesamen(pp, x_("circle-arc"), l) == 0 && l >= 8) np = art_circleprim;
1531 	if (namesamen(pp, x_("text"), l) == 0 && l >= 1) np = gen_invispinprim;
1532 
1533 	if (np == NONODEPROTO)
1534 	{
1535 		ttyputerr(_("Unrecoginzed shape: '%s'"), pp);
1536 		return;
1537 	}
1538 
1539 	/* make sure the cell is right */
1540 	cell = us_needcell();
1541 	if (cell == NONODEPROTO) return;
1542 	if (namesamen(cell->protoname, x_("node-"), 5) != 0 &&
1543 		namesamen(cell->protoname, x_("arc-"), 4) != 0)
1544 	{
1545 		us_abortcommand(_("Must be editing a node or arc to place geometry"));
1546 		if ((us_tool->toolstate&NODETAILS) == 0)
1547 			ttyputmsg(_("Use 'edit-node' or 'edit-arc' options"));
1548 		return;
1549 	}
1550 	if (np == gen_portprim &&
1551 		namesamen(cell->protoname, x_("node-"), 5) != 0)
1552 	{
1553 		us_abortcommand(_("Can only place ports in node descriptions"));
1554 		if ((us_tool->toolstate&NODETAILS) == 0)
1555 			ttyputmsg(_("Use the 'edit-node' options"));
1556 		return;
1557 	}
1558 
1559 	/* create the node */
1560 	us_clearhighlightcount();
1561 	savenp = us_curnodeproto;
1562 	us_curnodeproto = np;
1563 	subpar[0] = x_("wait-for-down");
1564 	us_create(1, subpar);
1565 	us_curnodeproto = savenp;
1566 
1567 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
1568 	if (var == NOVARIABLE) return;
1569 	(void)us_makehighlight(((CHAR **)var->addr)[0], &high);
1570 	if (high.fromgeom == NOGEOM) return;
1571 	if (!high.fromgeom->entryisnode) return;
1572 	ni = high.fromgeom->entryaddr.ni;
1573 	(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
1574 
1575 	/* postprocessing on the nodes */
1576 	if (namesamen(pp, x_("port"), l) == 0 && l >= 1)
1577 	{
1578 		/* a port layer */
1579 		if (count == 1)
1580 		{
1581 			name = ttygetline(M_("Port name: "));
1582 			if (name == 0 || name[0] == 0)
1583 			{
1584 				us_abortedmsg();
1585 				return;
1586 			}
1587 		} else name = par[1];
1588 		var = setval((INTBIG)ni, VNODEINST, x_("EDTEC_portname"), (INTBIG)name, VSTRING|VDISPLAY);
1589 		if (var != NOVARIABLE) defaulttextdescript(var->textdescript, ni->geom);
1590 		if ((us_tool->toolstate&NODETAILS) == 0)
1591 			ttyputmsg(_("Use 'change' option to set arc connectivity and port angle"));
1592 	}
1593 	if (namesamen(pp, x_("highlight"), l) == 0 && l >= 1)
1594 	{
1595 		/* a highlight layer */
1596 		us_teceditsetpatch(ni, &us_edtechigh);
1597 		(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"), (INTBIG)NONODEPROTO, VNODEPROTO);
1598 		ttyputmsg(_("Keep highlight a constant distance from the example edge"));
1599 	}
1600 	if (namesamen(pp, x_("circle-half"), l) == 0 && l >= 8)
1601 		setarcdegrees(ni, 0.0, 180.0*EPI/180.0);
1602 	if ((us_tool->toolstate&NODETAILS) == 0)
1603 	{
1604 		if (namesamen(pp, x_("rectangle-"), 10) == 0)
1605 			ttyputmsg(_("Use 'change' option to set a layer for this shape"));
1606 		if (namesamen(pp, x_("polygon-"), 8) == 0)
1607 		{
1608 			ttyputmsg(_("Use 'change' option to set a layer for this shape"));
1609 			ttyputmsg(_("Use 'outline edit' to describe polygonal shape"));
1610 		}
1611 		if (namesamen(pp, x_("lines-"), 6) == 0)
1612 			ttyputmsg(_("Use 'change' option to set a layer for this line"));
1613 		if (namesamen(pp, x_("circle-"), 7) == 0)
1614 			ttyputmsg(_("Use 'change' option to set a layer for this circle"));
1615 		if (namesamen(pp, x_("text"), l) == 0 && l >= 1)
1616 		{
1617 			ttyputmsg(_("Use 'change' option to set a layer for this text"));
1618 			ttyputmsg(_("Use 'var textedit ~.ART_message' command to set text"));
1619 			ttyputmsg(_("Then use 'var change ~.ART_message display' command"));
1620 		}
1621 	}
1622 	if (namesamen(pp, x_("circle-arc"), l) == 0 && l >= 8)
1623 	{
1624 		setarcdegrees(ni, 0.0, 45.0*EPI/180.0);
1625 		if ((us_tool->toolstate&NODETAILS) == 0)
1626 			ttyputmsg(_("Use 'setarc' command to set portion of circle"));
1627 	}
1628 	if ((ni->proto->userbits&HOLDSTRACE) != 0)
1629 	{
1630 		/* give it real points if it holds an outline */
1631 		subpar[0] = x_("trace");
1632 		subpar[1] = x_("init-points");
1633 		us_node(2, subpar);
1634 	}
1635 }
1636 
1637 /*
1638  * routine to highlight information about all layers (or ports if "doports" is true)
1639  */
us_teceditidentify(BOOLEAN doports)1640 void us_teceditidentify(BOOLEAN doports)
1641 {
1642 	REGISTER NODEPROTO *np;
1643 	REGISTER INTBIG total, qtotal, i, j, bestrot, indent;
1644 	REGISTER INTBIG xsep, ysep, *xpos, *ypos, dist, bestdist, *style;
1645 	INTBIG lx, hx, ly, hy;
1646 	REGISTER EXAMPLE *nelist;
1647 	REGISTER SAMPLE *ns, **whichsam;
1648 	static POLYGON *poly = NOPOLYGON;
1649 	extern GRAPHICS us_hbox;
1650 
1651 	np = us_needcell();
1652 	if (np == NONODEPROTO) return;
1653 
1654 	if (doports)
1655 	{
1656 		if (namesamen(np->protoname, x_("node-"), 5) != 0)
1657 		{
1658 			us_abortcommand(_("Must be editing a node to identify ports"));
1659 			if ((us_tool->toolstate&NODETAILS) == 0)
1660 				ttyputmsg(M_("Use the 'edit-node' option"));
1661 			return;
1662 		}
1663 	} else
1664 	{
1665 		if (namesamen(np->protoname, x_("node-"), 5) != 0 &&
1666 			namesamen(np->protoname, x_("arc-"), 4) != 0)
1667 		{
1668 			us_abortcommand(_("Must be editing a node or arc to identify layers"));
1669 			if ((us_tool->toolstate&NODETAILS) == 0)
1670 				ttyputmsg(M_("Use 'edit-node' or 'edit-arc' options"));
1671 			return;
1672 		}
1673 	}
1674 
1675 	/* get examples */
1676 	if (namesamen(np->protoname, x_("node-"), 5) == 0)
1677 		nelist = us_tecedgetexamples(np, TRUE); else
1678 			nelist = us_tecedgetexamples(np, FALSE);
1679 	if (nelist == NOEXAMPLE) return;
1680 
1681 	/* count the number of appropriate samples in the main example */
1682 	total = 0;
1683 	for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1684 	{
1685 		if (!doports)
1686 		{
1687 			if (ns->layer != gen_portprim) total++;
1688 		} else
1689 		{
1690 			if (ns->layer == gen_portprim) total++;
1691 		}
1692 	}
1693 	if (total == 0)
1694 	{
1695 		us_tecedfreeexamples(nelist);
1696 		us_abortcommand(_("There are no %s to identify"), (!doports ? _("layers") : _("ports")));
1697 		return;
1698 	}
1699 
1700 	/* make arrays for position and association */
1701 	xpos = (INTBIG *)emalloc(total * SIZEOFINTBIG, el_tempcluster);
1702 	if (xpos == 0) return;
1703 	ypos = (INTBIG *)emalloc(total * SIZEOFINTBIG, el_tempcluster);
1704 	if (ypos == 0) return;
1705 	style = (INTBIG *)emalloc(total * SIZEOFINTBIG, el_tempcluster);
1706 	if (style == 0) return;
1707 	whichsam = (SAMPLE **)emalloc(total * (sizeof (SAMPLE *)), el_tempcluster);
1708 	if (whichsam == 0) return;
1709 
1710 	/* fill in label positions */
1711 	qtotal = (total+3) / 4;
1712 	ysep = (el_curwindowpart->screenhy-el_curwindowpart->screenly) / qtotal;
1713 	xsep = (el_curwindowpart->screenhx-el_curwindowpart->screenlx) / qtotal;
1714 	indent = (el_curwindowpart->screenhy-el_curwindowpart->screenly) / 15;
1715 	for(i=0; i<qtotal; i++)
1716 	{
1717 		/* label on the left side */
1718 		xpos[i] = el_curwindowpart->screenlx + indent;
1719 		ypos[i] = el_curwindowpart->screenly + ysep * i + ysep/2;
1720 		style[i] = TEXTLEFT;
1721 		if (i+qtotal < total)
1722 		{
1723 			/* label on the top side */
1724 			xpos[i+qtotal] = el_curwindowpart->screenlx + xsep * i + xsep/2;
1725 			ypos[i+qtotal] = el_curwindowpart->screenhy - indent;
1726 			style[i+qtotal] = TEXTTOP;
1727 		}
1728 		if (i+qtotal*2 < total)
1729 		{
1730 			/* label on the right side */
1731 			xpos[i+qtotal*2] = el_curwindowpart->screenhx - indent;
1732 			ypos[i+qtotal*2] = el_curwindowpart->screenly + ysep * i + ysep/2;
1733 			style[i+qtotal*2] = TEXTRIGHT;
1734 		}
1735 		if (i+qtotal*3 < total)
1736 		{
1737 			/* label on the bottom side */
1738 			xpos[i+qtotal*3] = el_curwindowpart->screenlx + xsep * i + xsep/2;
1739 			ypos[i+qtotal*3] = el_curwindowpart->screenly + indent;
1740 			style[i+qtotal*3] = TEXTBOT;
1741 		}
1742 	}
1743 
1744 	/* fill in sample associations */
1745 	i = 0;
1746 	for(ns = nelist->firstsample; ns != NOSAMPLE; ns = ns->nextsample)
1747 	{
1748 		if (!doports)
1749 		{
1750 			if (ns->layer != gen_portprim) whichsam[i++] = ns;
1751 		} else
1752 		{
1753 			if (ns->layer == gen_portprim) whichsam[i++] = ns;
1754 		}
1755 	}
1756 
1757 	/* rotate through all configurations, finding least distance */
1758 	bestdist = MAXINTBIG;
1759 	for(i=0; i<total; i++)
1760 	{
1761 		/* find distance from each label to its sample center */
1762 		dist = 0;
1763 		for(j=0; j<total; j++)
1764 			dist += computedistance(xpos[j], ypos[j], whichsam[j]->xpos, whichsam[j]->ypos);
1765 		if (dist < bestdist)
1766 		{
1767 			bestdist = dist;
1768 			bestrot = i;
1769 		}
1770 
1771 		/* rotate the samples */
1772 		ns = whichsam[0];
1773 		for(j=1; j<total; j++) whichsam[j-1] = whichsam[j];
1774 		whichsam[total-1] = ns;
1775 	}
1776 
1777 	/* rotate back to the best orientation */
1778 	for(i=0; i<bestrot; i++)
1779 	{
1780 		ns = whichsam[0];
1781 		for(j=1; j<total; j++) whichsam[j-1] = whichsam[j];
1782 		whichsam[total-1] = ns;
1783 	}
1784 
1785 	/* get polygon */
1786 	(void)needstaticpolygon(&poly, 2, us_tool->cluster);
1787 
1788 	/* draw the highlighting */
1789 	us_clearhighlightcount();
1790 	for(i=0; i<total; i++)
1791 	{
1792 		ns = whichsam[i];
1793 		poly->xv[0] = xpos[i];
1794 		poly->yv[0] = ypos[i];
1795 		poly->count = 1;
1796 		if (ns->layer == NONODEPROTO)
1797 		{
1798 			poly->string = x_("HIGHLIGHT");
1799 		} else if (ns->layer == gen_cellcenterprim)
1800 		{
1801 			poly->string = x_("GRAB");
1802 		} else if (ns->layer == gen_portprim)
1803 		{
1804 			poly->string = us_tecedgetportname(ns->node);
1805 			if (poly->string == 0) poly->string = x_("?");
1806 		} else poly->string = &ns->layer->protoname[6];
1807 		poly->desc = &us_hbox;
1808 		poly->style = style[i];
1809 		TDCLEAR(poly->textdescript);
1810 		TDSETSIZE(poly->textdescript, TXTSETQLAMBDA(4));
1811 		poly->tech = el_curtech;
1812 		us_hbox.col = HIGHLIT;
1813 
1814 		nodesizeoffset(ns->node, &lx, &ly, &hx, &hy);
1815 		switch (poly->style)
1816 		{
1817 			case TEXTLEFT:
1818 				poly->xv[1] = ns->node->lowx+lx;
1819 				poly->yv[1] = (ns->node->lowy + ns->node->highy) / 2;
1820 				poly->style = TEXTBOTLEFT;
1821 				break;
1822 			case TEXTRIGHT:
1823 				poly->xv[1] = ns->node->highx-hx;
1824 				poly->yv[1] = (ns->node->lowy + ns->node->highy) / 2;
1825 				poly->style = TEXTBOTRIGHT;
1826 				break;
1827 			case TEXTTOP:
1828 				poly->xv[1] = (ns->node->lowx + ns->node->highx) / 2;
1829 				poly->yv[1] = ns->node->highy-hy;
1830 				poly->style = TEXTTOPLEFT;
1831 				break;
1832 			case TEXTBOT:
1833 				poly->xv[1] = (ns->node->lowx + ns->node->highx) / 2;
1834 				poly->yv[1] = ns->node->lowy+ly;
1835 				poly->style = TEXTBOTLEFT;
1836 				break;
1837 		}
1838 		us_showpoly(poly, el_curwindowpart);
1839 
1840 		/* now draw the vector polygon */
1841 		poly->count = 2;
1842 		poly->style = VECTORS;
1843 		us_showpoly(poly, el_curwindowpart);
1844 	}
1845 
1846 	/* free rotation arrays */
1847 	efree((CHAR *)xpos);
1848 	efree((CHAR *)ypos);
1849 	efree((CHAR *)style);
1850 	efree((CHAR *)whichsam);
1851 
1852 	/* free all examples */
1853 	us_tecedfreeexamples(nelist);
1854 }
1855 
1856 /*
1857  * routine to print information about selected object
1858  */
us_teceditinquire(void)1859 void us_teceditinquire(void)
1860 {
1861 	REGISTER NODEINST *ni;
1862 	REGISTER ARCINST *ai;
1863 	REGISTER NODEPROTO *np;
1864 	REGISTER CHAR *pt1, *pt2, *pt;
1865 	REGISTER VARIABLE *var;
1866 	REGISTER INTBIG opt;
1867 	REGISTER HIGHLIGHT *high;
1868 
1869 	high = us_getonehighlight();
1870 	if ((high->status&HIGHTYPE) != HIGHTEXT && (high->status&HIGHTYPE) != HIGHFROM)
1871 	{
1872 		us_abortcommand(_("Must select a single object for inquiry"));
1873 		return;
1874 	}
1875 	if ((high->status&HIGHTYPE) == HIGHFROM && !high->fromgeom->entryisnode)
1876 	{
1877 		/* describe currently highlighted arc */
1878 		ai = high->fromgeom->entryaddr.ai;
1879 		if (ai->proto != gen_universalarc)
1880 		{
1881 			ttyputmsg(_("This is an unimportant %s arc"), describearcproto(ai->proto));
1882 			return;
1883 		}
1884 		if (ai->end[0].nodeinst->proto != gen_portprim ||
1885 			ai->end[1].nodeinst->proto != gen_portprim)
1886 		{
1887 			ttyputmsg(_("This arc makes an unimportant connection"));
1888 			return;
1889 		}
1890 		pt1 = us_tecedgetportname(ai->end[0].nodeinst);
1891 		pt2 = us_tecedgetportname(ai->end[1].nodeinst);
1892 		if (pt1 == 0 || pt2 == 0)
1893 			ttyputmsg(_("This arc connects two port objects")); else
1894 				ttyputmsg(_("This arc connects ports '%s' and '%s'"), pt1, pt2);
1895 		return;
1896 	}
1897 	ni = high->fromgeom->entryaddr.ni;
1898 	np = ni->parent;
1899 	opt = us_tecedgetoption(ni);
1900 	if (opt < 0)
1901 	{
1902 		ttyputmsg(_("This object has no relevance to technology editing"));
1903 		return;
1904 	}
1905 
1906 	switch (opt)
1907 	{
1908 		case ARCFIXANG:
1909 			ttyputmsg(_("This object defines the fixed-angle factor of %s"), describenodeproto(np));
1910 			break;
1911 		case ARCFUNCTION:
1912 			ttyputmsg(_("This object defines the function of %s"), describenodeproto(np));
1913 			break;
1914 		case ARCINC:
1915 			ttyputmsg(_("This object defines the prefered angle increment of %s"), describenodeproto(np));
1916 			break;
1917 		case ARCNOEXTEND:
1918 			ttyputmsg(_("This object defines the arc extension of %s"), describenodeproto(np));
1919 			break;
1920 		case ARCWIPESPINS:
1921 			ttyputmsg(_("This object defines the arc coverage of %s"), describenodeproto(np));
1922 			break;
1923 		case CENTEROBJ:
1924 			ttyputmsg(_("This object identifies the grab point of %s"), describenodeproto(np));
1925 			break;
1926 		case LAYER3DHEIGHT:
1927 			ttyputmsg(_("This object defines the 3D height of %s"), describenodeproto(np));
1928 			break;
1929 		case LAYER3DTHICK:
1930 			ttyputmsg(_("This object defines the 3D thickness of %s"), describenodeproto(np));
1931 			break;
1932 		case LAYERPRINTCOL:
1933 			ttyputmsg(_("This object defines the print colors of %s"), describenodeproto(np));
1934 			break;
1935 		case LAYERCIF:
1936 			ttyputmsg(_("This object defines the CIF name of %s"), describenodeproto(np));
1937 			break;
1938 		case LAYERCOLOR:
1939 			ttyputmsg(_("This object defines the color of %s"), describenodeproto(np));
1940 			break;
1941 		case LAYERDXF:
1942 			ttyputmsg(_("This object defines the DXF name(s) of %s"), describenodeproto(np));
1943 			break;
1944 		case LAYERDRCMINWID:
1945 			ttyputmsg(_("This object defines the minimum DRC width of %s (OBSOLETE)"), describenodeproto(np));
1946 			break;
1947 		case LAYERFUNCTION:
1948 			ttyputmsg(_("This object defines the function of %s"), describenodeproto(np));
1949 			break;
1950 		case LAYERGDS:
1951 			ttyputmsg(_("This object defines the Calma GDS-II number of %s"), describenodeproto(np));
1952 			break;
1953 		case LAYERLETTERS:
1954 			ttyputmsg(_("This object defines the letters to use for %s"), describenodeproto(np));
1955 			break;
1956 		case LAYERPATCONT:
1957 			ttyputmsg(_("This object provides control of the stipple pattern in %s"), describenodeproto(np));
1958 			break;
1959 		case LAYERPATTERN:
1960 			ttyputmsg(_("This is one of the bitmap squares in %s"), describenodeproto(np));
1961 			break;
1962 		case LAYERSPICAP:
1963 			ttyputmsg(_("This object defines the SPICE capacitance of %s"), describenodeproto(np));
1964 			break;
1965 		case LAYERSPIECAP:
1966 			ttyputmsg(_("This object defines the SPICE edge capacitance of %s"), describenodeproto(np));
1967 			break;
1968 		case LAYERSPIRES:
1969 			ttyputmsg(_("This object defines the SPICE resistance of %s"), describenodeproto(np));
1970 			break;
1971 		case LAYERSTYLE:
1972 			ttyputmsg(_("This object defines the style of %s"), describenodeproto(np));
1973 			break;
1974 		case LAYERPATCH:
1975 		case HIGHLIGHTOBJ:
1976 			np = us_tecedgetlayer(ni);
1977 			if (np == 0)
1978 				ttyputerr(_("This is an object with no valid layer!")); else
1979 			{
1980 				if (np == NONODEPROTO) ttyputmsg(_("This is a highlight box")); else
1981 					ttyputmsg(_("This is a '%s' layer"), &np->protoname[6]);
1982 				var = getval((INTBIG)ni, VNODEINST, VSTRING, x_("EDTEC_minbox"));
1983 				if (var != NOVARIABLE)
1984 					ttyputmsg(_("   It is at minimum size"));
1985 			}
1986 			break;
1987 		case NODEFUNCTION:
1988 			ttyputmsg(_("This object defines the function of %s"), describenodeproto(np));
1989 			break;
1990 		case NODELOCKABLE:
1991 			ttyputmsg(_("This object tells if %s can be locked (used in array technologies)"),
1992 				describenodeproto(np));
1993 			break;
1994 		case NODEMULTICUT:
1995 			ttyputmsg(_("This object tells the separation between multiple contact cuts in %s"),
1996 				describenodeproto(np));
1997 			break;
1998 		case NODESERPENTINE:
1999 			ttyputmsg(_("This object tells if %s is a serpentine transistor"), describenodeproto(np));
2000 			break;
2001 		case NODESQUARE:
2002 			ttyputmsg(_("This object tells if %s is square"), describenodeproto(np));
2003 			break;
2004 		case NODEWIPES:
2005 			ttyputmsg(_("This object tells if %s disappears when conencted to one or two arcs"),
2006 				describenodeproto(np));
2007 			break;
2008 		case PORTOBJ:
2009 			pt = us_tecedgetportname(ni);
2010 			if (pt == 0) ttyputmsg(_("This is a port object")); else
2011 				ttyputmsg(_("This is port '%s'"), pt);
2012 			break;
2013 		case TECHDESCRIPT:
2014 			ttyputmsg(_("This object contains the technology description"));
2015 			break;
2016 		case TECHLAMBDA:
2017 			ttyputmsg(_("This object defines the value of lambda"));
2018 			break;
2019 		default:
2020 			ttyputerr(_("This object has unknown information"));
2021 			break;
2022 	}
2023 }
2024 
2025 /*
2026  * Routine to return a brief description of node "ni" for use in the status area.
2027  */
us_teceddescribenode(NODEINST * ni)2028 CHAR *us_teceddescribenode(NODEINST *ni)
2029 {
2030 	REGISTER INTBIG opt;
2031 	REGISTER NODEPROTO *np;
2032 	REGISTER void *infstr;
2033 	REGISTER CHAR *pt;
2034 
2035 	opt = us_tecedgetoption(ni);
2036 	if (opt < 0) return(0);
2037 	switch (opt)
2038 	{
2039 		case ARCFIXANG:      return(_("Arc fixed-angle factor"));
2040 		case ARCFUNCTION:    return(_("Arc function"));
2041 		case ARCINC:         return(_("Arc angle increment"));
2042 		case ARCNOEXTEND:    return(_("Arc extension"));
2043 		case ARCWIPESPINS:   return(_("Arc coverage"));
2044 		case CENTEROBJ:      return(_("Grab point"));
2045 		case LAYER3DHEIGHT:  return(_("3D height"));
2046 		case LAYER3DTHICK:   return(_("3D thickness"));
2047 		case LAYERPRINTCOL:  return(_("Print colors"));
2048 		case LAYERCIF:       return(_("CIF names"));
2049 		case LAYERCOLOR:     return(_("Layer color"));
2050 		case LAYERDXF:       return(_("DXF name(s)"));
2051 		case LAYERFUNCTION:  return(_("Layer function"));
2052 		case LAYERGDS:       return(_("GDS-II number(s)"));
2053 		case LAYERLETTERS:   return(_("Layer letters"));
2054 		case LAYERPATCONT:   return(_("Pattern control"));
2055 		case LAYERPATTERN:   return(_("Stipple pattern element"));
2056 		case LAYERSPICAP:    return(_("Spice capacitance"));
2057 		case LAYERSPIECAP:   return(_("Spice edge capacitance"));
2058 		case LAYERSPIRES:    return(_("Spice resistance"));
2059 		case LAYERSTYLE:     return(_("Srawing style"));
2060 		case LAYERPATCH:
2061 		case HIGHLIGHTOBJ:
2062 			np = us_tecedgetlayer(ni);
2063 			if (np == 0) return(_("Unknown layer"));
2064 			if (np == NONODEPROTO) return(_("Highlight box"));
2065 			infstr = initinfstr();
2066 			formatinfstr(infstr, _("Layer %s"), &np->protoname[6]);
2067 			return(returninfstr(infstr));
2068 		case NODEFUNCTION:   return(_("Node function"));
2069 		case NODELOCKABLE:   return(_("Node lockability"));
2070 		case NODEMULTICUT:   return(_("Multicut separation"));
2071 		case NODESERPENTINE: return(_("Serpentine transistor"));
2072 		case NODESQUARE:     return(_("Square node"));
2073 		case NODEWIPES:      return(_("Disappearing pin"));
2074 		case PORTOBJ:
2075 			pt = us_tecedgetportname(ni);
2076 			if (pt == 0) return(_("Unnamed export"));
2077 			infstr = initinfstr();
2078 			formatinfstr(infstr, _("Export %s"), pt);
2079 			return(returninfstr(infstr));
2080 		case TECHDESCRIPT:   return(_("Technology description"));
2081 		case TECHLAMBDA:     return(_("Lambda value"));
2082 	}
2083 	return(0);
2084 }
2085 
2086 /*
2087  * routine for modifying the selected object.  If two are selected, connect them.
2088  */
us_teceditmodobject(INTBIG count,CHAR * par[])2089 void us_teceditmodobject(INTBIG count, CHAR *par[])
2090 {
2091 	REGISTER NODEINST *ni;
2092 	GEOM *fromgeom, *togeom, **list;
2093 	PORTPROTO *fromport, *toport;
2094 	INTBIG opt, textcount, i, found;
2095 	REGISTER HIGHLIGHT *high;
2096 	HIGHLIGHT newhigh;
2097 	CHAR *newpar[2], **textinfo;
2098 
2099 	/* special case for pattern changes */
2100 	list = us_gethighlighted(WANTNODEINST|WANTARCINST, &textcount, &textinfo);
2101 	if (textcount == 0)
2102 	{
2103 		found = 0;
2104 		for(i=0; list[i] != NOGEOM; i++)
2105 		{
2106 			if (!list[i]->entryisnode) continue;
2107 			ni = list[i]->entryaddr.ni;
2108 			opt = us_tecedgetoption(ni);
2109 			if (opt == LAYERPATTERN) found++;
2110 		}
2111 		if (found > 0)
2112 		{
2113 			/* change them */
2114 			us_clearhighlightcount();
2115 			for(i=0; list[i] != NOGEOM; i++)
2116 			{
2117 				if (!list[i]->entryisnode) continue;
2118 				ni = list[i]->entryaddr.ni;
2119 				opt = us_tecedgetoption(ni);
2120 				if (opt == LAYERPATTERN)
2121 					us_tecedlayerpattern(ni);
2122 			}
2123 			return;
2124 		}
2125 	}
2126 
2127 	/* if two are highlighted, connect them */
2128 	if (!us_gettwoobjects(&fromgeom, &fromport, &togeom, &toport))
2129 	{
2130 		newpar[0] = x_("angle");   newpar[1] = x_("0");
2131 		us_create(2, newpar);
2132 		return;
2133 	}
2134 
2135 	/* make sure something is highlighted */
2136 	high = us_getonehighlight();
2137 	if (high == NOHIGHLIGHT) return;
2138 
2139 	/* must be one node highlighted */
2140 	ni = (NODEINST *)us_getobject(VNODEINST, TRUE);
2141 	if (ni == NONODEINST) return;
2142 
2143 	/* determine technology editor relevance */
2144 	opt = us_tecedgetoption(ni);
2145 
2146 	/* special case for port modification: reset highlighting by hand */
2147 	if (opt == PORTOBJ)
2148 	{
2149 		/* pick up old highlight values and then remove highlighting */
2150 		newhigh = *high;
2151 		us_clearhighlightcount();
2152 
2153 		/* modify the port */
2154 		us_tecedmodport(ni, count, par);
2155 
2156 		/* set new highlighting variable */
2157 		newhigh.fromvar = getval((INTBIG)ni, VNODEINST, VSTRING, x_("EDTEC_portname"));
2158 		if (newhigh.fromvar == NOVARIABLE)
2159 			newhigh.fromvar = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
2160 		us_addhighlight(&newhigh);
2161 		return;
2162 	}
2163 
2164 	/* ignore if no parameter given */
2165 	if (count <= 0) return;
2166 
2167 	/* handle other cases */
2168 	us_pushhighlight();
2169 	us_clearhighlightcount();
2170 	switch (opt)
2171 	{
2172 		case ARCFIXANG:      us_tecedarcfixang(ni, count, par);      break;
2173 		case ARCFUNCTION:    us_tecedarcfunction(ni, count, par);    break;
2174 		case ARCINC:         us_tecedarcinc(ni, count, par);         break;
2175 		case ARCNOEXTEND:    us_tecedarcnoextend(ni, count, par);    break;
2176 		case ARCWIPESPINS:   us_tecedarcwipes(ni, count, par);       break;
2177 		case LAYER3DHEIGHT:  us_tecedlayer3dheight(ni, count, par);  break;
2178 		case LAYER3DTHICK:   us_tecedlayer3dthick(ni, count, par);   break;
2179 		case LAYERPRINTCOL:  us_tecedlayerprintcol(ni, count, par);  break;
2180 		case LAYERCIF:       us_tecedlayercif(ni, count, par);       break;
2181 		case LAYERCOLOR:     us_tecedlayercolor(ni, count, par);     break;
2182 		case LAYERDXF:       us_tecedlayerdxf(ni, count, par);       break;
2183 		case LAYERDRCMINWID: us_tecedlayerdrcminwid(ni, count, par); break;
2184 		case LAYERFUNCTION:  us_tecedlayerfunction(ni, count, par);  break;
2185 		case LAYERGDS:       us_tecedlayergds(ni, count, par);       break;
2186 		case LAYERLETTERS:   us_tecedlayerletters(ni, count, par);   break;
2187 		case LAYERPATCONT:   us_tecedlayerpatterncontrol(ni, count, par);   break;
2188 		case LAYERPATCH:     us_tecedlayertype(ni, count, par);      break;
2189 		case LAYERSPICAP:    us_tecedlayerspicap(ni, count, par);    break;
2190 		case LAYERSPIECAP:   us_tecedlayerspiecap(ni, count, par);   break;
2191 		case LAYERSPIRES:    us_tecedlayerspires(ni, count, par);    break;
2192 		case LAYERSTYLE:     us_tecedlayerstyle(ni, count, par);     break;
2193 		case NODEFUNCTION:   us_tecednodefunction(ni, count, par);   break;
2194 		case NODELOCKABLE:   us_tecednodelockable(ni, count, par);   break;
2195 		case NODEMULTICUT:   us_tecednodemulticut(ni, count, par);   break;
2196 		case NODESERPENTINE: us_tecednodeserpentine(ni, count, par); break;
2197 		case NODESQUARE:     us_tecednodesquare(ni, count, par);     break;
2198 		case NODEWIPES:      us_tecednodewipes(ni, count, par);      break;
2199 		case TECHDESCRIPT:   us_tecedinfodescript(ni, count, par);   break;
2200 		case TECHLAMBDA:     us_tecedinfolambda(ni, count, par);     break;
2201 		default:             us_abortcommand(_("Cannot modify this object"));   break;
2202 	}
2203 	us_pophighlight(FALSE);
2204 }
2205 
2206 /***************************** OBJECT MODIFICATION *****************************/
2207 
us_tecedlayer3dheight(NODEINST * ni,INTBIG count,CHAR * par[])2208 void us_tecedlayer3dheight(NODEINST *ni, INTBIG count, CHAR *par[])
2209 {
2210 	REGISTER void *infstr;
2211 
2212 	if (par[0][0] == 0)
2213 	{
2214 		us_abortcommand(_("Enter the height of the layer when viewed in 3D"));
2215 		return;
2216 	}
2217 	infstr = initinfstr();
2218 	addstringtoinfstr(infstr, TECEDNODETEXT3DHEIGHT);
2219 	addstringtoinfstr(infstr, par[0]);
2220 	us_tecedsetnode(ni, returninfstr(infstr));
2221 }
2222 
us_tecedlayer3dthick(NODEINST * ni,INTBIG count,CHAR * par[])2223 void us_tecedlayer3dthick(NODEINST *ni, INTBIG count, CHAR *par[])
2224 {
2225 	REGISTER void *infstr;
2226 
2227 	if (par[0][0] == 0)
2228 	{
2229 		us_abortcommand(_("Enter the thickness of the layer when viewed in 3D"));
2230 		return;
2231 	}
2232 	infstr = initinfstr();
2233 	addstringtoinfstr(infstr, TECEDNODETEXT3DTHICK);
2234 	addstringtoinfstr(infstr, par[0]);
2235 	us_tecedsetnode(ni, returninfstr(infstr));
2236 }
2237 
us_tecedlayerprintcol(NODEINST * ni,INTBIG count,CHAR * par[])2238 void us_tecedlayerprintcol(NODEINST *ni, INTBIG count, CHAR *par[])
2239 {
2240 	REGISTER void *infstr;
2241 	INTBIG len, r, g, b, o, f;
2242 	REGISTER VARIABLE *var;
2243 
2244 	if (count < 2)
2245 	{
2246 		ttyputverbose(_("Enter the print colors of the layer"));
2247 		return;
2248 	}
2249 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
2250 	us_teceditgetprintcol(var, &r, &g, &b, &o, &f);
2251 	len = estrlen(par[0]);
2252 	if (namesamen(par[0], x_("red"), len) == 0) r = myatoi(par[1]); else
2253 	if (namesamen(par[0], x_("green"), len) == 0) g = myatoi(par[1]); else
2254 	if (namesamen(par[0], x_("blue"), len) == 0) b = myatoi(par[1]); else
2255 	if (namesamen(par[0], x_("opacity"), len) == 0) o = myatoi(par[1]); else
2256 	if (namesamen(par[0], x_("foreground"), len) == 0)
2257 	{
2258 		if (namesame(par[1], x_("on")) == 0) f = 1; else
2259 			if (namesame(par[1], x_("off")) == 0) f = 0; else
2260 				f = myatoi(par[1]);
2261 	}
2262 	infstr = initinfstr();
2263 	addstringtoinfstr(infstr, TECEDNODETEXTPRINTCOL);
2264 	formatinfstr(infstr, x_("%ld,%ld,%ld, %ld,%s"), r, g, b, o, (f==0 ? x_("off") : x_("on")));
2265 	us_tecedsetnode(ni, returninfstr(infstr));
2266 }
2267 
us_tecedlayerdrcminwid(NODEINST * ni,INTBIG count,CHAR * par[])2268 void us_tecedlayerdrcminwid(NODEINST *ni, INTBIG count, CHAR *par[])
2269 {
2270 	REGISTER void *infstr;
2271 
2272 	if (par[0][0] == 0)
2273 	{
2274 		us_abortcommand(_("Enter the minimum DRC width (negative for none)"));
2275 		return;
2276 	}
2277 	infstr = initinfstr();
2278 	addstringtoinfstr(infstr, TECEDNODETEXTDRCMINWID);
2279 	addstringtoinfstr(infstr, par[0]);
2280 	us_tecedsetnode(ni, returninfstr(infstr));
2281 }
2282 
us_tecedlayercolor(NODEINST * ni,INTBIG count,CHAR * par[])2283 void us_tecedlayercolor(NODEINST *ni, INTBIG count, CHAR *par[])
2284 {
2285 	REGISTER void *infstr;
2286 
2287 	if (par[0][0] == 0)
2288 	{
2289 		us_abortcommand(_("New color required"));
2290 		return;
2291 	}
2292 	infstr = initinfstr();
2293 	addstringtoinfstr(infstr, TECEDNODETEXTCOLOR);
2294 	addstringtoinfstr(infstr, par[0]);
2295 	us_tecedsetnode(ni, returninfstr(infstr));
2296 
2297 	/* redraw the demo layer in this cell */
2298 	us_tecedredolayergraphics(ni->parent);
2299 }
2300 
us_tecedlayerstyle(NODEINST * ni,INTBIG count,CHAR * par[])2301 void us_tecedlayerstyle(NODEINST *ni, INTBIG count, CHAR *par[])
2302 {
2303 	REGISTER void *infstr;
2304 
2305 	if (par[0][0] == 0)
2306 	{
2307 		us_abortcommand(_("Layer style required"));
2308 		return;
2309 	}
2310 	infstr = initinfstr();
2311 	addstringtoinfstr(infstr, TECEDNODETEXTSTYLE);
2312 	addstringtoinfstr(infstr, par[0]);
2313 	us_tecedsetnode(ni, returninfstr(infstr));
2314 
2315 	/* redraw the demo layer in this cell */
2316 	us_tecedredolayergraphics(ni->parent);
2317 }
2318 
us_tecedlayercif(NODEINST * ni,INTBIG count,CHAR * par[])2319 void us_tecedlayercif(NODEINST *ni, INTBIG count, CHAR *par[])
2320 {
2321 	REGISTER void *infstr;
2322 
2323 	infstr = initinfstr();
2324 	addstringtoinfstr(infstr, TECEDNODETEXTCIF);
2325 	addstringtoinfstr(infstr, par[0]);
2326 	us_tecedsetnode(ni, returninfstr(infstr));
2327 }
2328 
us_tecedlayerdxf(NODEINST * ni,INTBIG count,CHAR * par[])2329 void us_tecedlayerdxf(NODEINST *ni, INTBIG count, CHAR *par[])
2330 {
2331 	REGISTER void *infstr;
2332 
2333 	infstr = initinfstr();
2334 	addstringtoinfstr(infstr, TECEDNODETEXTDXF);
2335 	addstringtoinfstr(infstr, par[0]);
2336 	us_tecedsetnode(ni, returninfstr(infstr));
2337 }
2338 
us_tecedlayergds(NODEINST * ni,INTBIG count,CHAR * par[])2339 void us_tecedlayergds(NODEINST *ni, INTBIG count, CHAR *par[])
2340 {
2341 	REGISTER void *infstr;
2342 
2343 	infstr = initinfstr();
2344 	addstringtoinfstr(infstr, TECEDNODETEXTGDS);
2345 	addstringtoinfstr(infstr, par[0]);
2346 	us_tecedsetnode(ni, returninfstr(infstr));
2347 }
2348 
us_tecedlayerspires(NODEINST * ni,INTBIG count,CHAR * par[])2349 void us_tecedlayerspires(NODEINST *ni, INTBIG count, CHAR *par[])
2350 {
2351 	REGISTER void *infstr;
2352 
2353 	if (par[0][0] == 0)
2354 	{
2355 		us_abortcommand(_("Enter the SPICE layer resistance"));
2356 		return;
2357 	}
2358 	infstr = initinfstr();
2359 	addstringtoinfstr(infstr, TECEDNODETEXTSPICERES);
2360 	addstringtoinfstr(infstr, par[0]);
2361 	us_tecedsetnode(ni, returninfstr(infstr));
2362 }
2363 
us_tecedlayerspicap(NODEINST * ni,INTBIG count,CHAR * par[])2364 void us_tecedlayerspicap(NODEINST *ni, INTBIG count, CHAR *par[])
2365 {
2366 	REGISTER void *infstr;
2367 
2368 	if (par[0][0] == 0)
2369 	{
2370 		us_abortcommand(_("Enter the SPICE layer capacitance"));
2371 		return;
2372 	}
2373 	infstr = initinfstr();
2374 	addstringtoinfstr(infstr, TECEDNODETEXTSPICECAP);
2375 	addstringtoinfstr(infstr, par[0]);
2376 	us_tecedsetnode(ni, returninfstr(infstr));
2377 }
2378 
us_tecedlayerspiecap(NODEINST * ni,INTBIG count,CHAR * par[])2379 void us_tecedlayerspiecap(NODEINST *ni, INTBIG count, CHAR *par[])
2380 {
2381 	REGISTER void *infstr;
2382 
2383 	if (par[0][0] == 0)
2384 	{
2385 		us_abortcommand(_("Enter the SPICE layer edge capacitance"));
2386 		return;
2387 	}
2388 	infstr = initinfstr();
2389 	addstringtoinfstr(infstr, TECEDNODETEXTSPICEECAP);
2390 	addstringtoinfstr(infstr, par[0]);
2391 	us_tecedsetnode(ni, returninfstr(infstr));
2392 }
2393 
us_tecedlayerfunction(NODEINST * ni,INTBIG count,CHAR * par[])2394 void us_tecedlayerfunction(NODEINST *ni, INTBIG count, CHAR *par[])
2395 {
2396 	REGISTER INTBIG func, newfunc;
2397 	REGISTER CHAR *str;
2398 	REGISTER VARIABLE *var;
2399 	REGISTER void *infstr;
2400 
2401 	if (par[0][0] == 0)
2402 	{
2403 		us_abortcommand(_("Layer function required"));
2404 		return;
2405 	}
2406 
2407 	/* get the existing function */
2408 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
2409 	func = 0;
2410 	if (var != NOVARIABLE)
2411 	{
2412 		str = (CHAR *)var->addr;
2413 		while (*str != 0 && *str != ':') str++;
2414 		if (*str == ':') str++;
2415 		while (*str == ' ') str++;
2416 		if (*str != 0) func = us_teceditparsefun(str);
2417 	}
2418 
2419 	/* add in the new function */
2420 	newfunc = us_teceditparsefun(par[0]);
2421 	if (newfunc <= LFTYPE) func = newfunc; else func |= newfunc;
2422 
2423 	/* build the string corresponding to this function */
2424 	infstr = initinfstr();
2425 	addstringtoinfstr(infstr, TECEDNODETEXTFUNCTION);
2426 	us_tecedaddfunstring(infstr, func);
2427 
2428 	/* rewrite the node with the new function */
2429 	us_tecedsetnode(ni, returninfstr(infstr));
2430 }
2431 
us_tecedlayerletters(NODEINST * ni,INTBIG count,CHAR * par[])2432 void us_tecedlayerletters(NODEINST *ni, INTBIG count, CHAR *par[])
2433 {
2434 	REGISTER NODEPROTO *np;
2435 	REGISTER CHAR *pt;
2436 	REGISTER INTBIG i;
2437 	CHAR *cif, *layerletters, *dxf, *gds;
2438 	GRAPHICS desc;
2439 	float spires, spicap, spiecap;
2440 	INTBIG func, drcminwid, height3d, thick3d, printcol[5];
2441 	REGISTER void *infstr;
2442 
2443 	if (par[0][0] == 0)
2444 	{
2445 		us_abortcommand(_("Layer letter(s) required"));
2446 		return;
2447 	}
2448 
2449 	/* check layer letters for uniqueness */
2450 	for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2451 	{
2452 		if (namesamen(np->protoname, x_("layer-"), 6) != 0) continue;
2453 		cif = layerletters = gds = 0;
2454 		if (us_teceditgetlayerinfo(np, &desc, &cif, &func, &layerletters,
2455 			&dxf, &gds, &spires, &spicap, &spiecap, &drcminwid, &height3d,
2456 				&thick3d, printcol)) return;
2457 		if (gds != 0) efree(gds);
2458 		if (cif != 0) efree(cif);
2459 		if (layerletters == 0) continue;
2460 
2461 		/* check these layer letters for uniqueness */
2462 		for(pt = layerletters; *pt != 0; pt++)
2463 		{
2464 			for(i=0; par[0][i] != 0; i++) if (par[0][i] == *pt)
2465 			{
2466 				us_abortcommand(_("Cannot use letter '%c', it is in %s"), *pt, describenodeproto(np));
2467 				efree(layerletters);
2468 				return;
2469 			}
2470 		}
2471 		efree(layerletters);
2472 	}
2473 
2474 	infstr = initinfstr();
2475 	addstringtoinfstr(infstr, TECEDNODETEXTLETTERS);
2476 	addstringtoinfstr(infstr, par[0]);
2477 	us_tecedsetnode(ni, returninfstr(infstr));
2478 }
2479 
us_tecedlayerpatterncontrol(NODEINST * ni,INTBIG count,CHAR * par[])2480 void us_tecedlayerpatterncontrol(NODEINST *ni, INTBIG count, CHAR *par[])
2481 {
2482 	REGISTER INTBIG len;
2483 	REGISTER NODEINST *pni;
2484 	REGISTER INTBIG opt;
2485 	UINTSML color;
2486 	static GRAPHICS desc;
2487 	static BOOLEAN didcopy = FALSE;
2488 	CHAR *cif, *layerletters, *gds, *dxf;
2489 	INTBIG func, drcminwid, height3d, thick3d, printcol[5];
2490 	float spires, spicap, spiecap;
2491 
2492 	len = estrlen(par[0]);
2493 	if (namesamen(par[0], x_("Clear Pattern"), len) == 0 && len > 2)
2494 	{
2495 		us_clearhighlightcount();
2496 		for(pni = ni->parent->firstnodeinst; pni != NONODEINST; pni = pni->nextnodeinst)
2497 		{
2498 			opt = us_tecedgetoption(pni);
2499 			if (opt != LAYERPATTERN) continue;
2500 			color = us_tecedlayergetpattern(pni);
2501 			if (color != 0)
2502 				us_tecedlayersetpattern(pni, 0);
2503 		}
2504 
2505 		/* redraw the demo layer in this cell */
2506 		us_tecedredolayergraphics(ni->parent);
2507 		return;
2508 	}
2509 	if (namesamen(par[0], x_("Invert Pattern"), len) == 0 && len > 1)
2510 	{
2511 		us_clearhighlightcount();
2512 		for(pni = ni->parent->firstnodeinst; pni != NONODEINST; pni = pni->nextnodeinst)
2513 		{
2514 			opt = us_tecedgetoption(pni);
2515 			if (opt != LAYERPATTERN) continue;
2516 			color = us_tecedlayergetpattern(pni);
2517 			us_tecedlayersetpattern(pni, (INTSML)(~color));
2518 		}
2519 
2520 		/* redraw the demo layer in this cell */
2521 		us_tecedredolayergraphics(ni->parent);
2522 		return;
2523 	}
2524 	if (namesamen(par[0], x_("Copy Pattern"), len) == 0 && len > 2)
2525 	{
2526 		us_clearhighlightcount();
2527 		if (us_teceditgetlayerinfo(ni->parent, &desc, &cif, &func, &layerletters, &dxf,
2528 			&gds, &spires, &spicap, &spiecap, &drcminwid, &height3d, &thick3d, printcol)) return;
2529 		didcopy = TRUE;
2530 		return;
2531 	}
2532 	if (namesamen(par[0], x_("Paste Pattern"), len) == 0 && len > 1)
2533 	{
2534 		us_clearhighlightcount();
2535 		us_teceditsetlayerpattern(ni->parent, &desc);
2536 
2537 		/* redraw the demo layer in this cell */
2538 		us_tecedredolayergraphics(ni->parent);
2539 		return;
2540 	}
2541 }
2542 
2543 /*
2544  * Routine to return the color in layer-pattern node "ni" (off is 0, on is 0xFFFF).
2545  */
us_tecedlayergetpattern(NODEINST * ni)2546 INTSML us_tecedlayergetpattern(NODEINST *ni)
2547 {
2548 	REGISTER VARIABLE *var;
2549 	REGISTER INTSML color;
2550 
2551 	if (ni->proto == art_boxprim) return(0);
2552 	if (ni->proto == art_filledboxprim)
2553 	{
2554 		var = getvalkey((INTBIG)ni, VNODEINST, VSHORT|VISARRAY, art_patternkey);
2555 		if (var == NOVARIABLE) color = (INTSML)0xFFFF; else color = ((INTSML *)var->addr)[0];
2556 		return(color);
2557 	}
2558 	return(0);
2559 }
2560 
2561 /*
2562  * Routine to set layer-pattern node "ni" to be color "color" (off is 0, on is 0xFFFF).
2563  * Returns the address of the node (may be different than "ni" if it had to be replaced).
2564  */
us_tecedlayersetpattern(NODEINST * ni,INTSML color)2565 NODEINST *us_tecedlayersetpattern(NODEINST *ni, INTSML color)
2566 {
2567 	REGISTER NODEINST *newni;
2568 	INTBIG i;
2569 	UINTSML col[16];
2570 
2571 	if (ni->proto == art_boxprim)
2572 	{
2573 		if (color == 0) return(ni);
2574 		startobjectchange((INTBIG)ni, VNODEINST);
2575 		newni = replacenodeinst(ni, art_filledboxprim, FALSE, FALSE);
2576 		if (newni == NONODEINST) return(ni);
2577 		endobjectchange((INTBIG)newni, VNODEINST);
2578 		ni = newni;
2579 	} else if (ni->proto == art_filledboxprim)
2580 	{
2581 		startobjectchange((INTBIG)ni, VNODEINST);
2582 		for(i=0; i<16; i++) col[i] = color;
2583 		(void)setvalkey((INTBIG)ni, VNODEINST, art_patternkey, (INTBIG)col,
2584 			VSHORT|VISARRAY|(16<<VLENGTHSH));
2585 		endobjectchange((INTBIG)ni, VNODEINST);
2586 	}
2587 	return(ni);
2588 }
2589 
2590 /*
2591  * Routine to toggle the color of layer-pattern node "ni" (called when the user does a
2592  * "technology edit" click on the node).
2593  */
us_tecedlayerpattern(NODEINST * ni)2594 void us_tecedlayerpattern(NODEINST *ni)
2595 {
2596 	HIGHLIGHT high;
2597 	UINTSML color;
2598 
2599 	color = us_tecedlayergetpattern(ni);
2600 	ni = us_tecedlayersetpattern(ni, (INTSML)(~color));
2601 
2602 	high.status = HIGHFROM;
2603 	high.cell = ni->parent;
2604 	high.fromgeom = ni->geom;
2605 	high.fromport = NOPORTPROTO;
2606 	high.frompoint = 0;
2607 	high.fromvar = NOVARIABLE;
2608 	high.fromvarnoeval = NOVARIABLE;
2609 	us_addhighlight(&high);
2610 
2611 	/* redraw the demo layer in this cell */
2612 	us_tecedredolayergraphics(ni->parent);
2613 }
2614 
2615 /*
2616  * routine to modify the layer information in node "ni".
2617  */
us_tecedlayertype(NODEINST * ni,INTBIG count,CHAR * par[])2618 void us_tecedlayertype(NODEINST *ni, INTBIG count, CHAR *par[])
2619 {
2620 	REGISTER NODEPROTO *np;
2621 	CHAR *cif, *layerletters, *dxf, *gds;
2622 	REGISTER CHAR *name;
2623 	GRAPHICS desc;
2624 	float spires, spicap, spiecap;
2625 	INTBIG func, drcminwid, height3d, thick3d, printcol[5];
2626 	REGISTER void *infstr;
2627 
2628 	if (par[0][0] == 0)
2629 	{
2630 		us_abortcommand(_("Requires a layer name"));
2631 		return;
2632 	}
2633 
2634 	np = us_needcell();
2635 	if (np == NONODEPROTO) return;
2636 	if (namesame(par[0], x_("SET-MINIMUM-SIZE")) == 0)
2637 	{
2638 		if (namesamen(np->protoname, x_("node-"), 5) != 0)
2639 		{
2640 			us_abortcommand(_("Can only set minimum size in node descriptions"));
2641 			if ((us_tool->toolstate&NODETAILS) == 0) ttyputmsg(_("Use 'edit-node' option"));
2642 			return;
2643 		}
2644 		startobjectchange((INTBIG)ni, VNODEINST);
2645 		(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_minbox"), (INTBIG)x_("MIN"), VSTRING|VDISPLAY);
2646 		endobjectchange((INTBIG)ni, VNODEINST);
2647 		return;
2648 	}
2649 
2650 	if (namesame(par[0], x_("CLEAR-MINIMUM-SIZE")) == 0)
2651 	{
2652 		if (getval((INTBIG)ni, VNODEINST, VSTRING, x_("EDTEC_minbox")) == NOVARIABLE)
2653 		{
2654 			ttyputmsg(_("Minimum size is not set on this layer"));
2655 			return;
2656 		}
2657 		startobjectchange((INTBIG)ni, VNODEINST);
2658 		(void)delval((INTBIG)ni, VNODEINST, x_("EDTEC_minbox"));
2659 		endobjectchange((INTBIG)ni, VNODEINST);
2660 		return;
2661 	}
2662 
2663 	/* find the actual cell with that layer specification */
2664 	infstr = initinfstr();
2665 	addstringtoinfstr(infstr, x_("layer-"));
2666 	addstringtoinfstr(infstr, par[0]);
2667 	name = returninfstr(infstr);
2668 	np = getnodeproto(name);
2669 	if (np == NONODEPROTO)
2670 	{
2671 		ttyputerr(_("Cannot find layer primitive %s"), name);
2672 		return;
2673 	}
2674 
2675 	/* get the characteristics of that layer */
2676 	cif = layerletters = gds = 0;
2677 	if (us_teceditgetlayerinfo(np, &desc, &cif, &func, &layerletters,
2678 		&dxf, &gds, &spires, &spicap, &spiecap, &drcminwid, &height3d,
2679 			&thick3d, printcol)) return;
2680 	if (gds != 0) efree(gds);
2681 	if (cif != 0) efree(cif);
2682 	if (layerletters != 0) efree(layerletters);
2683 
2684 	startobjectchange((INTBIG)ni, VNODEINST);
2685 	us_teceditsetpatch(ni, &desc);
2686 	(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"), (INTBIG)np, VNODEPROTO);
2687 	endobjectchange((INTBIG)ni, VNODEINST);
2688 }
2689 
2690 /*
2691  * routine to modify port characteristics
2692  */
us_tecedmodport(NODEINST * ni,INTBIG count,CHAR * par[])2693 void us_tecedmodport(NODEINST *ni, INTBIG count, CHAR *par[])
2694 {
2695 	REGISTER INTBIG total, i, len, j, yes;
2696 	BOOLEAN changed;
2697 	REGISTER BOOLEAN *yesno;
2698 	REGISTER NODEPROTO *np, **conlist;
2699 	REGISTER VARIABLE *var;
2700 
2701 	/* build an array of arc connections */
2702 	for(total = 0, np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2703 		if (namesamen(np->protoname, x_("arc-"), 4) == 0) total++;
2704 	conlist = (NODEPROTO **)emalloc(total * (sizeof (NODEPROTO *)), el_tempcluster);
2705 	if (conlist == 0) return;
2706 	for(total = 0, np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2707 		if (namesamen(np->protoname, x_("arc-"), 4) == 0) conlist[total++] = np;
2708 	yesno = (BOOLEAN *)emalloc(total * (sizeof (BOOLEAN)), el_tempcluster);
2709 	if (yesno == 0) return;
2710 	for(i=0; i<total; i++) yesno[i] = FALSE;
2711 
2712 	/* put current list into the array */
2713 	var = getval((INTBIG)ni, VNODEINST, VNODEPROTO|VISARRAY, x_("EDTEC_connects"));
2714 	if (var != NOVARIABLE)
2715 	{
2716 		len = getlength(var);
2717 		for(j=0; j<len; j++)
2718 		{
2719 			for(i=0; i<total; i++)
2720 				if (conlist[i] == ((NODEPROTO **)var->addr)[j]) break;
2721 			if (i < total) yesno[i] = TRUE;
2722 		}
2723 	}
2724 
2725 	/* parse the command parameters */
2726 	changed = FALSE;
2727 	for(i=0; i<count-1; i += 2)
2728 	{
2729 		/* search for an arc name */
2730 		for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2731 			if (namesamen(np->protoname, x_("arc-"), 4) == 0 &&
2732 				namesame(&np->protoname[4], par[i]) == 0) break;
2733 		if (np != NONODEPROTO)
2734 		{
2735 			for(j=0; j<total; j++) if (conlist[j] == np)
2736 			{
2737 				if (*par[i+1] == 'y' || *par[i+1] == 'Y') yesno[j] = TRUE; else
2738 					yesno[j] = FALSE;
2739 				changed = TRUE;
2740 				break;
2741 			}
2742 			continue;
2743 		}
2744 
2745 		if (namesame(par[i], x_("PORT-ANGLE")) == 0)
2746 		{
2747 			(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_portangle"), myatoi(par[i+1]), VINTEGER);
2748 			continue;
2749 		}
2750 		if (namesame(par[i], x_("PORT-ANGLE-RANGE")) == 0)
2751 		{
2752 			(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_portrange"), myatoi(par[i+1]), VINTEGER);
2753 			continue;
2754 		}
2755 	}
2756 
2757 	/* store list back if it was changed */
2758 	if (changed)
2759 	{
2760 		yes = 0;
2761 		for(i=0; i<total; i++)
2762 		{
2763 			if (!yesno[i]) continue;
2764 			conlist[yes++] = conlist[i];
2765 		}
2766 		if (yes == 0 && var != NOVARIABLE)
2767 			(void)delval((INTBIG)ni, VNODEINST, x_("EDTEC_connects")); else
2768 		{
2769 			(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_connects"), (INTBIG)conlist,
2770 				VNODEPROTO|VISARRAY|(yes<<VLENGTHSH));
2771 		}
2772 	}
2773 	efree((CHAR *)conlist);
2774 	efree((CHAR *)yesno);
2775 }
2776 
us_tecedarcfunction(NODEINST * ni,INTBIG count,CHAR * par[])2777 void us_tecedarcfunction(NODEINST *ni, INTBIG count, CHAR *par[])
2778 {
2779 	REGISTER void *infstr;
2780 
2781 	if (par[0][0] == 0)
2782 	{
2783 		us_abortcommand(_("Requires a layer function"));
2784 		return;
2785 	}
2786 	infstr = initinfstr();
2787 	addstringtoinfstr(infstr, TECEDNODETEXTFUNCTION);
2788 	addstringtoinfstr(infstr, par[0]);
2789 	us_tecedsetnode(ni, returninfstr(infstr));
2790 }
2791 
us_tecedarcfixang(NODEINST * ni,INTBIG count,CHAR * par[])2792 void us_tecedarcfixang(NODEINST *ni, INTBIG count, CHAR *par[])
2793 {
2794 	REGISTER void *infstr;
2795 
2796 	if (par[0][0] == 0)
2797 	{
2798 		us_abortcommand(_("Requires a yes or no"));
2799 		return;
2800 	}
2801 	infstr = initinfstr();
2802 	addstringtoinfstr(infstr, x_("Fixed-angle: "));
2803 	addstringtoinfstr(infstr, par[0]);
2804 	us_tecedsetnode(ni, returninfstr(infstr));
2805 }
2806 
us_tecedarcwipes(NODEINST * ni,INTBIG count,CHAR * par[])2807 void us_tecedarcwipes(NODEINST *ni, INTBIG count, CHAR *par[])
2808 {
2809 	REGISTER void *infstr;
2810 
2811 	if (par[0][0] == 0)
2812 	{
2813 		us_abortcommand(_("Requires a yes or no"));
2814 		return;
2815 	}
2816 	infstr = initinfstr();
2817 	addstringtoinfstr(infstr, x_("Wipes pins: "));
2818 	addstringtoinfstr(infstr, par[0]);
2819 	us_tecedsetnode(ni, returninfstr(infstr));
2820 }
2821 
us_tecedarcnoextend(NODEINST * ni,INTBIG count,CHAR * par[])2822 void us_tecedarcnoextend(NODEINST *ni, INTBIG count, CHAR *par[])
2823 {
2824 	REGISTER void *infstr;
2825 
2826 	if (par[0][0] == 0)
2827 	{
2828 		us_abortcommand(_("Requires a yes or no"));
2829 		return;
2830 	}
2831 	infstr = initinfstr();
2832 	addstringtoinfstr(infstr, x_("Extend arcs: "));
2833 	addstringtoinfstr(infstr, par[0]);
2834 	us_tecedsetnode(ni, returninfstr(infstr));
2835 }
2836 
us_tecedarcinc(NODEINST * ni,INTBIG count,CHAR * par[])2837 void us_tecedarcinc(NODEINST *ni, INTBIG count, CHAR *par[])
2838 {
2839 	REGISTER void *infstr;
2840 
2841 	if (par[0][0] == 0)
2842 	{
2843 		us_abortcommand(_("Requires an angle increment in degrees"));
2844 		return;
2845 	}
2846 	infstr = initinfstr();
2847 	addstringtoinfstr(infstr, x_("Angle increment: "));
2848 	addstringtoinfstr(infstr, par[0]);
2849 	us_tecedsetnode(ni, returninfstr(infstr));
2850 }
2851 
us_tecednodefunction(NODEINST * ni,INTBIG count,CHAR * par[])2852 void us_tecednodefunction(NODEINST *ni, INTBIG count, CHAR *par[])
2853 {
2854 	REGISTER void *infstr;
2855 
2856 	if (par[0][0] == 0)
2857 	{
2858 		us_abortcommand(_("Requires a node function"));
2859 		return;
2860 	}
2861 	infstr = initinfstr();
2862 	addstringtoinfstr(infstr, TECEDNODETEXTFUNCTION);
2863 	addstringtoinfstr(infstr, par[0]);
2864 	us_tecedsetnode(ni, returninfstr(infstr));
2865 }
2866 
us_tecednodeserpentine(NODEINST * ni,INTBIG count,CHAR * par[])2867 void us_tecednodeserpentine(NODEINST *ni, INTBIG count, CHAR *par[])
2868 {
2869 	REGISTER void *infstr;
2870 
2871 	if (par[0][0] == 0)
2872 	{
2873 		us_abortcommand(_("Requires a yes or no"));
2874 		return;
2875 	}
2876 	infstr = initinfstr();
2877 	addstringtoinfstr(infstr, x_("Serpentine transistor: "));
2878 	addstringtoinfstr(infstr, par[0]);
2879 	us_tecedsetnode(ni, returninfstr(infstr));
2880 }
2881 
us_tecednodesquare(NODEINST * ni,INTBIG count,CHAR * par[])2882 void us_tecednodesquare(NODEINST *ni, INTBIG count, CHAR *par[])
2883 {
2884 	REGISTER void *infstr;
2885 
2886 	if (par[0][0] == 0)
2887 	{
2888 		us_abortcommand(_("Requires a yes or no"));
2889 		return;
2890 	}
2891 	infstr = initinfstr();
2892 	addstringtoinfstr(infstr, x_("Square node: "));
2893 	addstringtoinfstr(infstr, par[0]);
2894 	us_tecedsetnode(ni, returninfstr(infstr));
2895 }
2896 
us_tecednodewipes(NODEINST * ni,INTBIG count,CHAR * par[])2897 void us_tecednodewipes(NODEINST *ni, INTBIG count, CHAR *par[])
2898 {
2899 	REGISTER void *infstr;
2900 
2901 	if (par[0][0] == 0)
2902 	{
2903 		us_abortcommand(_("Requires a yes or no"));
2904 		return;
2905 	}
2906 	infstr = initinfstr();
2907 	addstringtoinfstr(infstr, x_("Invisible with 1 or 2 arcs: "));
2908 	addstringtoinfstr(infstr, par[0]);
2909 	us_tecedsetnode(ni, returninfstr(infstr));
2910 }
2911 
us_tecednodelockable(NODEINST * ni,INTBIG count,CHAR * par[])2912 void us_tecednodelockable(NODEINST *ni, INTBIG count, CHAR *par[])
2913 {
2914 	REGISTER void *infstr;
2915 
2916 	if (par[0][0] == 0)
2917 	{
2918 		us_abortcommand(_("Requires a yes or no"));
2919 		return;
2920 	}
2921 	infstr = initinfstr();
2922 	addstringtoinfstr(infstr, x_("Lockable: "));
2923 	addstringtoinfstr(infstr, par[0]);
2924 	us_tecedsetnode(ni, returninfstr(infstr));
2925 }
2926 
us_tecednodemulticut(NODEINST * ni,INTBIG count,CHAR * par[])2927 void us_tecednodemulticut(NODEINST *ni, INTBIG count, CHAR *par[])
2928 {
2929 	REGISTER void *infstr;
2930 
2931 	if (par[0][0] == 0)
2932 	{
2933 		us_abortcommand(_("Requires a separation distance (0 for none)"));
2934 		return;
2935 	}
2936 	infstr = initinfstr();
2937 	addstringtoinfstr(infstr, x_("Multicut separation: "));
2938 	addstringtoinfstr(infstr, par[0]);
2939 	us_tecedsetnode(ni, returninfstr(infstr));
2940 }
2941 
us_tecedinfolambda(NODEINST * ni,INTBIG count,CHAR * par[])2942 void us_tecedinfolambda(NODEINST *ni, INTBIG count, CHAR *par[])
2943 {
2944 	REGISTER void *infstr;
2945 
2946 	if (par[0][0] == 0)
2947 	{
2948 		us_abortcommand(_("Requires a value of lambda"));
2949 		return;
2950 	}
2951 	infstr = initinfstr();
2952 	addstringtoinfstr(infstr, x_("Lambda: "));
2953 	addstringtoinfstr(infstr, par[0]);
2954 	us_tecedsetnode(ni, returninfstr(infstr));
2955 }
2956 
us_tecedinfodescript(NODEINST * ni,INTBIG count,CHAR * par[])2957 void us_tecedinfodescript(NODEINST *ni, INTBIG count, CHAR *par[])
2958 {
2959 	REGISTER void *infstr;
2960 
2961 	if (par[0][0] == 0)
2962 	{
2963 		us_abortcommand(_("Requires a technology description"));
2964 		return;
2965 	}
2966 	infstr = initinfstr();
2967 	addstringtoinfstr(infstr, x_("Description: "));
2968 	addstringtoinfstr(infstr, par[0]);
2969 	us_tecedsetnode(ni, returninfstr(infstr));
2970 }
2971 
2972 /****************************** UTILITIES ******************************/
2973 
us_tecedsetnode(NODEINST * ni,CHAR * chr)2974 void us_tecedsetnode(NODEINST *ni, CHAR *chr)
2975 {
2976 	UINTBIG descript[TEXTDESCRIPTSIZE];
2977 	REGISTER VARIABLE *var;
2978 	CHAR *newmsg;
2979 
2980 	allocstring(&newmsg, chr, el_tempcluster);
2981 	startobjectchange((INTBIG)ni, VNODEINST);
2982 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
2983 	if (var == NOVARIABLE) TDCLEAR(descript); else TDCOPY(descript, var->textdescript);
2984 	var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)newmsg, VSTRING|VDISPLAY);
2985 	if (var != NOVARIABLE) modifydescript((INTBIG)ni, VNODEINST, var, descript);
2986 	endobjectchange((INTBIG)ni, VNODEINST);
2987 	efree((CHAR *)newmsg);
2988 }
2989 
2990 /*
2991  * routine to call up the cell "cellname" (either create it or reedit it)
2992  * returns NONODEPROTO if there is an error or the cell exists
2993  */
us_tecedentercell(CHAR * cellname)2994 NODEPROTO *us_tecedentercell(CHAR *cellname)
2995 {
2996 	REGISTER NODEPROTO *np;
2997 	CHAR *newpar[2];
2998 
2999 	np = getnodeproto(cellname);
3000 	if (np != NONODEPROTO && np->primindex == 0)
3001 	{
3002 		newpar[0] = x_("editcell");
3003 		newpar[1] = cellname;
3004 		telltool(us_tool, 2, newpar);
3005 		return(NONODEPROTO);
3006 	}
3007 
3008 	/* create the cell */
3009 	np = newnodeproto(cellname, el_curlib);
3010 	if (np == NONODEPROTO) return(NONODEPROTO);
3011 
3012 	/* now edit the cell */
3013 	newpar[0] = x_("editcell");
3014 	newpar[1] = cellname;
3015 	telltool(us_tool, 2, newpar);
3016 	return(np);
3017 }
3018 
3019 /*
3020  * routine to redraw the demo layer in "layer" cell "np"
3021  */
us_tecedredolayergraphics(NODEPROTO * np)3022 void us_tecedredolayergraphics(NODEPROTO *np)
3023 {
3024 	REGISTER VARIABLE *var;
3025 	REGISTER NODEINST *ni;
3026 	GRAPHICS desc;
3027 	REGISTER NODEPROTO *onp;
3028 	CHAR *cif, *layerletters, *dxf, *gds;
3029 	INTBIG func, drcminwid, height3d, thick3d, printcol[5];
3030 	float spires, spicap, spiecap;
3031 
3032 	/* find the demo patch in this cell */
3033 	var = getval((INTBIG)np, VNODEPROTO, VNODEINST, x_("EDTEC_colornode"));
3034 	if (var == NOVARIABLE) return;
3035 	ni = (NODEINST *)var->addr;
3036 
3037 	/* get the current description of this layer */
3038 	cif = layerletters = gds = 0;
3039 	if (us_teceditgetlayerinfo(np, &desc, &cif, &func, &layerletters,
3040 		&dxf, &gds, &spires, &spicap, &spiecap, &drcminwid, &height3d,
3041 			&thick3d, printcol)) return;
3042 	if (gds != 0) efree(gds);
3043 	if (cif != 0) efree(cif);
3044 	if (layerletters != 0) efree(layerletters);
3045 
3046 	/* modify the demo patch to reflect the color and pattern */
3047 	startobjectchange((INTBIG)ni, VNODEINST);
3048 	us_teceditsetpatch(ni, &desc);
3049 	endobjectchange((INTBIG)ni, VNODEINST);
3050 
3051 	/* now do this to all layers in all cells! */
3052 	for(onp = el_curlib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3053 	{
3054 		if (namesamen(onp->protoname, x_("arc-"), 4) != 0 &&
3055 			namesamen(onp->protoname, x_("node-"), 5) != 0) continue;
3056 		for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3057 		{
3058 			if (us_tecedgetoption(ni) != LAYERPATCH) continue;
3059 			var = getval((INTBIG)ni, VNODEINST, VNODEPROTO, x_("EDTEC_layer"));
3060 			if (var == NOVARIABLE) continue;
3061 			if ((NODEPROTO *)var->addr != np) continue;
3062 			us_teceditsetpatch(ni, &desc);
3063 		}
3064 	}
3065 }
3066 
us_teceditsetpatch(NODEINST * ni,GRAPHICS * desc)3067 void us_teceditsetpatch(NODEINST *ni, GRAPHICS *desc)
3068 {
3069 	REGISTER INTBIG i;
3070 	UINTBIG pattern[16];
3071 	UINTSML spattern[16];
3072 
3073 	(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, desc->col, VINTEGER);
3074 	if ((desc->colstyle&NATURE) == PATTERNED)
3075 	{
3076 		if ((desc->colstyle&OUTLINEPAT) == 0)
3077 		{
3078 			for(i=0; i<16; i++) pattern[i] = desc->raster[i];
3079 			(void)setvalkey((INTBIG)ni, VNODEINST, art_patternkey, (INTBIG)pattern,
3080 				VINTEGER|VISARRAY|(16<<VLENGTHSH));
3081 		} else
3082 		{
3083 			for(i=0; i<16; i++) spattern[i] = desc->raster[i];
3084 			(void)setvalkey((INTBIG)ni, VNODEINST, art_patternkey, (INTBIG)spattern,
3085 				VSHORT|VISARRAY|(16<<VLENGTHSH));
3086 		}
3087 	} else
3088 	{
3089 		if (getvalkey((INTBIG)ni, VNODEINST, -1, art_patternkey) != NOVARIABLE)
3090 			(void)delvalkey((INTBIG)ni, VNODEINST, art_patternkey);
3091 	}
3092 }
3093 
3094 /*
3095  * routine to load the color map associated with library "lib"
3096  */
us_tecedloadlibmap(LIBRARY * lib)3097 void us_tecedloadlibmap(LIBRARY *lib)
3098 {
3099 	REGISTER VARIABLE *var;
3100 	REGISTER INTBIG i;
3101 	REGISTER INTBIG *mapptr;
3102 	INTBIG redmap[256], greenmap[256], bluemap[256];
3103 
3104 	var = getval((INTBIG)lib, VLIBRARY, VINTEGER|VISARRAY, x_("EDTEC_colormap"));
3105 	if (var != NOVARIABLE)
3106 	{
3107 		mapptr = (INTBIG *)var->addr;
3108 		for(i=0; i<256; i++)
3109 		{
3110 			redmap[i] = *mapptr++;
3111 			greenmap[i] = *mapptr++;
3112 			bluemap[i] = *mapptr++;
3113 		}
3114 
3115 		/* disable option tracking */
3116 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey, 1,
3117 			VINTEGER|VDONTSAVE);
3118 
3119 		startobjectchange((INTBIG)us_tool, VTOOL);
3120 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)redmap,
3121 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
3122 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)greenmap,
3123 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
3124 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)bluemap,
3125 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
3126 		endobjectchange((INTBIG)us_tool, VTOOL);
3127 
3128 		/* re-enable option tracking */
3129 		var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_ignoreoptionchangeskey);
3130 		if (var != NOVARIABLE)
3131 			(void)delvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey);
3132 	}
3133 }
3134 
3135 /*
3136  * routine to parse the layer cell in "np" and fill these reference descriptors:
3137  *   "desc" (a GRAPHICS structure)
3138  *   "cif" (the name of the CIF layer)
3139  *   "dxf" (the name of the DXF layer)
3140  *   "func" (the integer function number)
3141  *   "layerletters" (the letters associated with this layer),
3142  *   "gds" (the Calma GDS-II layer number)
3143  *   "spires" (the SPICE resistance)
3144  *   "spicap" (the SPICE capacitance)
3145  *   "spiecap" (the SPICE edge capacitance)
3146  *   "drcminwid" (the DRC minimum width)
3147  *   "height3d" (the 3D height)
3148  *   "thick3d" (the 3D thickness)
3149  *   "printcol" (the printer colors)
3150  * All of the reference parameters except "func", "spires", "spicap", and "spiecap"
3151  * get allocated.  Returns true on error.
3152  */
us_teceditgetlayerinfo(NODEPROTO * np,GRAPHICS * desc,CHAR ** cif,INTBIG * func,CHAR ** layerletters,CHAR ** dxf,CHAR ** gds,float * spires,float * spicap,float * spiecap,INTBIG * drcminwid,INTBIG * height3d,INTBIG * thick3d,INTBIG * printcol)3153 BOOLEAN us_teceditgetlayerinfo(NODEPROTO *np, GRAPHICS *desc, CHAR **cif, INTBIG *func,
3154 	CHAR **layerletters, CHAR **dxf, CHAR **gds, float *spires, float *spicap,
3155 	float *spiecap, INTBIG *drcminwid, INTBIG *height3d, INTBIG *thick3d, INTBIG *printcol)
3156 {
3157 	REGISTER NODEINST *ni;
3158 	REGISTER INTBIG patterncount, i, color, len;
3159 	REGISTER INTBIG lowx, highx, lowy, highy, x, y;
3160 	REGISTER CHAR *str;
3161 	REGISTER VARIABLE *var, *varkey;
3162 
3163 	/* create and initialize the GRAPHICS structure */
3164 	desc->colstyle = SOLIDC;
3165 	desc->bwstyle = PATTERNED;
3166 	for(i=0; i<16; i++) desc->raster[i] = 0;
3167 
3168 	/* look at all nodes in the layer description cell */
3169 	patterncount = 0;
3170 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3171 	{
3172 		varkey = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
3173 		if (varkey == NOVARIABLE) continue;
3174 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, art_messagekey);
3175 		if (var == NOVARIABLE) str = ""; else
3176 		{
3177 			str = (CHAR *)var->addr;
3178 			while (*str != 0 && *str != ':') str++;
3179 			if (*str == ':') str++;
3180 			while (*str == ' ') str++;
3181 		}
3182 
3183 		switch (varkey->addr)
3184 		{
3185 			case LAYERPATTERN:
3186 				if (patterncount == 0)
3187 				{
3188 					lowx = ni->lowx;   highx = ni->highx;
3189 					lowy = ni->lowy;   highy = ni->highy;
3190 				} else
3191 				{
3192 					if (ni->lowx < lowx) lowx = ni->lowx;
3193 					if (ni->highx > highx) highx = ni->highx;
3194 					if (ni->lowy < lowy) lowy = ni->lowy;
3195 					if (ni->highy > highy) highy = ni->highy;
3196 				}
3197 				patterncount++;
3198 				break;
3199 			case LAYERCOLOR:
3200 				color = getecolor(str);
3201 				if (color < 0)
3202 				{
3203 					ttyputerr(_("Unknown color '%s' in %s"), str, describenodeproto(np));
3204 					return(TRUE);
3205 				}
3206 				desc->col = color;
3207 				switch (color)
3208 				{
3209 					case COLORT1: desc->bits = LAYERT1; break;
3210 					case COLORT2: desc->bits = LAYERT2; break;
3211 					case COLORT3: desc->bits = LAYERT3; break;
3212 					case COLORT4: desc->bits = LAYERT4; break;
3213 					case COLORT5: desc->bits = LAYERT5; break;
3214 					default:      desc->bits = LAYERO;  break;
3215 				}
3216 				break;
3217 			case LAYERSTYLE:
3218 				if (namesame(str, x_("solid")) == 0)
3219 					desc->colstyle = desc->bwstyle = SOLIDC;
3220 				if (namesame(str, x_("patterned")) == 0)
3221 					desc->colstyle = desc->bwstyle = PATTERNED;
3222 				if (namesame(str, x_("patterned/outlined")) == 0)
3223 					desc->colstyle = desc->bwstyle = PATTERNED | OUTLINEPAT;
3224 				break;
3225 			case LAYERCIF:
3226 				if (allocstring(cif, str, us_tool->cluster)) return(TRUE);
3227 				break;
3228 			case LAYERDXF:
3229 				if (allocstring(dxf, str, us_tool->cluster)) return(TRUE);
3230 				break;
3231 			case LAYERGDS:
3232 				if (namesame(str, x_("-1")) == 0) str = x_("");
3233 				if (allocstring(gds, str, us_tool->cluster)) return(TRUE);
3234 				break;
3235 			case LAYERFUNCTION:
3236 				*func = us_teceditparsefun(str);
3237 				break;
3238 			case LAYERLETTERS:
3239 				if (allocstring(layerletters, str, us_tool->cluster)) return(TRUE);
3240 				break;
3241 			case LAYERSPIRES:
3242 				*spires = (float)eatof(str);
3243 				break;
3244 			case LAYERSPICAP:
3245 				*spicap = (float)eatof(str);
3246 				break;
3247 			case LAYERSPIECAP:
3248 				*spiecap = (float)eatof(str);
3249 				break;
3250 			case LAYERDRCMINWID:
3251 				*drcminwid = atofr(str);
3252 				break;
3253 			case LAYER3DHEIGHT:
3254 				*height3d = myatoi(str);
3255 				break;
3256 			case LAYER3DTHICK:
3257 				*thick3d = myatoi(str);
3258 				break;
3259 			case LAYERPRINTCOL:
3260 				us_teceditgetprintcol(var, &printcol[0], &printcol[1], &printcol[2],
3261 					&printcol[3], &printcol[4]);
3262 				break;
3263 		}
3264 	}
3265 
3266 	if (patterncount != 16*16 && patterncount != 16*8)
3267 	{
3268 		ttyputerr(_("Incorrect number of pattern boxes in %s (has %ld, not %d)"),
3269 			describenodeproto(np), patterncount, 16*16);
3270 		return(TRUE);
3271 	}
3272 
3273 	/* construct the pattern */
3274 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3275 	{
3276 		if (ni->proto != art_filledboxprim) continue;
3277 		var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
3278 		if (var == NOVARIABLE) continue;
3279 		if (var->addr != LAYERPATTERN) continue;
3280 		var = getvalkey((INTBIG)ni, VNODEINST, VSHORT|VISARRAY, art_patternkey);
3281 		if (var != NOVARIABLE)
3282 		{
3283 			len = getlength(var);
3284 			for(i=0; i<len; i++) if (((INTSML *)var->addr)[i] != 0) break;
3285 			if (i >= len) continue;
3286 		}
3287 		x = (ni->lowx - lowx) / ((highx-lowx) / 16);
3288 		y = (highy - ni->highy) / ((highy-lowy) / 16);
3289 		desc->raster[y] |= (1 << (15-x));
3290 	}
3291 	if (patterncount == 16*8)
3292 	{
3293 		/* older, half-height pattern: replicate it */
3294 		for(y=0; y<8; y++)
3295 			desc->raster[y+8] = desc->raster[y];
3296 	}
3297 	return(FALSE);
3298 }
3299 
us_teceditgetprintcol(VARIABLE * var,INTBIG * r,INTBIG * g,INTBIG * b,INTBIG * o,INTBIG * f)3300 void us_teceditgetprintcol(VARIABLE *var, INTBIG *r, INTBIG *g, INTBIG *b, INTBIG *o, INTBIG *f)
3301 {
3302 	REGISTER CHAR *pt;
3303 
3304 	/* set default values */
3305 	*r = *g = *b = *o = *f = 0;
3306 	if (var == NOVARIABLE) return;
3307 
3308 	/* skip the header */
3309 	pt = (CHAR *)var->addr;
3310 	while (*pt != 0 && *pt != ':') pt++;
3311 	if (*pt == ':') pt++;
3312 
3313 	/* get red */
3314 	while (*pt == ' ') pt++;
3315 	*r = myatoi(pt);
3316 	while (*pt != 0 && *pt != ',') pt++;
3317 	if (*pt == ',') pt++;
3318 
3319 	/* get green */
3320 	while (*pt == ' ') pt++;
3321 	*g = myatoi(pt);
3322 	while (*pt != 0 && *pt != ',') pt++;
3323 	if (*pt == ',') pt++;
3324 
3325 	/* get blue */
3326 	while (*pt == ' ') pt++;
3327 	*b = myatoi(pt);
3328 	while (*pt != 0 && *pt != ',') pt++;
3329 	if (*pt == ',') pt++;
3330 
3331 	/* get opacity */
3332 	while (*pt == ' ') pt++;
3333 	*o = myatoi(pt);
3334 	while (*pt != 0 && *pt != ',') pt++;
3335 	if (*pt == ',') pt++;
3336 
3337 	/* get foreground */
3338 	while (*pt == ' ') pt++;
3339 	if (namesamen(pt, x_("on"), 2) == 0) *f = 1; else
3340 		if (namesamen(pt, x_("off"), 3) == 0) *f = 0; else
3341 			*f = myatoi(pt);
3342 }
3343 
3344 /*
3345  * Routine to set the layer-pattern squares of cell "np" to the bits in "desc".
3346  */
us_teceditsetlayerpattern(NODEPROTO * np,GRAPHICS * desc)3347 void us_teceditsetlayerpattern(NODEPROTO *np, GRAPHICS *desc)
3348 {
3349 	REGISTER NODEINST *ni;
3350 	REGISTER INTBIG patterncount;
3351 	REGISTER INTBIG lowx, highx, lowy, highy, x, y;
3352 	REGISTER INTSML wantcolor, color;
3353 	REGISTER VARIABLE *var;
3354 
3355 	/* look at all nodes in the layer description cell */
3356 	patterncount = 0;
3357 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3358 	{
3359 		if (ni->proto == art_boxprim || ni->proto == art_filledboxprim)
3360 		{
3361 			var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
3362 			if (var == NOVARIABLE) continue;
3363 			if (var->addr != LAYERPATTERN) continue;
3364 			if (patterncount == 0)
3365 			{
3366 				lowx = ni->lowx;   highx = ni->highx;
3367 				lowy = ni->lowy;   highy = ni->highy;
3368 			} else
3369 			{
3370 				if (ni->lowx < lowx) lowx = ni->lowx;
3371 				if (ni->highx > highx) highx = ni->highx;
3372 				if (ni->lowy < lowy) lowy = ni->lowy;
3373 				if (ni->highy > highy) highy = ni->highy;
3374 			}
3375 			patterncount++;
3376 		}
3377 	}
3378 
3379 	if (patterncount != 16*16 && patterncount != 16*8)
3380 	{
3381 		ttyputerr(_("Incorrect number of pattern boxes in %s (has %ld, not %d)"),
3382 			describenodeproto(np), patterncount, 16*16);
3383 		return;
3384 	}
3385 
3386 	/* set the pattern */
3387 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3388 	{
3389 		if (ni->proto != art_boxprim && ni->proto != art_filledboxprim) continue;
3390 		var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
3391 		if (var == NOVARIABLE) continue;
3392 		if (var->addr != LAYERPATTERN) continue;
3393 
3394 		x = (ni->lowx - lowx) / ((highx-lowx) / 16);
3395 		y = (highy - ni->highy) / ((highy-lowy) / 16);
3396 		if ((desc->raster[y] & (1 << (15-x))) == 0) wantcolor = 0;
3397 			else wantcolor = (INTSML)0xFFFF;
3398 
3399 		color = us_tecedlayergetpattern(ni);
3400 		if (color != wantcolor)
3401 			us_tecedlayersetpattern(ni, wantcolor);
3402 	}
3403 }
3404 
3405 /*
3406  * routine to parse the layer function string "str" and return the
3407  * actual function codes
3408  */
us_teceditparsefun(CHAR * str)3409 INTBIG us_teceditparsefun(CHAR *str)
3410 {
3411 	REGISTER INTBIG func, save, i;
3412 	REGISTER CHAR *pt;
3413 
3414 	func = 0;
3415 	for(;;)
3416 	{
3417 		/* find the next layer function name */
3418 		pt = str;
3419 		while (*pt != 0 && *pt != ',') pt++;
3420 
3421 		/* parse the name */
3422 		save = *pt;
3423 		*pt = 0;
3424 		for(i=0; us_teclayer_functions[i].name != 0; i++)
3425 			if (namesame(str, us_teclayer_functions[i].name) == 0) break;
3426 		*pt = (CHAR)save;
3427 		if (us_teclayer_functions[i].name == 0)
3428 		{
3429 			ttyputerr(_("Unknown layer function: %s"), str);
3430 			return(0);
3431 		}
3432 
3433 		/* mix in the layer function */
3434 		if (us_teclayer_functions[i].value <= LFTYPE)
3435 		{
3436 			if (func != 0)
3437 			{
3438 				ttyputerr(_("Cannot be both function %s and %s"),
3439 					us_teclayer_functions[func&LFTYPE].name, us_teclayer_functions[i].name);
3440 				func = 0;
3441 			}
3442 			func = us_teclayer_functions[i].value;
3443 		} else func |= us_teclayer_functions[i].value;
3444 
3445 		/* advance to the next layer function name */
3446 		if (*pt == 0) break;
3447 		str = pt + 1;
3448 	}
3449 	return(func);
3450 }
3451 
3452 /*
3453  * routine to return the option index of node "ni"
3454  */
us_tecedgetoption(NODEINST * ni)3455 INTBIG us_tecedgetoption(NODEINST *ni)
3456 {
3457 	REGISTER VARIABLE *var, *var2;
3458 	REGISTER NODEPROTO *np;
3459 
3460 	/* port objects are readily identifiable */
3461 	if (ni->proto == gen_portprim) return(PORTOBJ);
3462 
3463 	/* center objects are also readily identifiable */
3464 	if (ni->proto == gen_cellcenterprim) return(CENTEROBJ);
3465 
3466 	var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
3467 	if (var == NOVARIABLE) return(-1);
3468 	if (var->addr == LAYERPATCH)
3469 	{
3470 		/* may be a highlight object */
3471 		var2 = getval((INTBIG)ni, VNODEINST, VNODEPROTO, x_("EDTEC_layer"));
3472 		if (var2 != NOVARIABLE)
3473 		{
3474 			np = (NODEPROTO *)var2->addr;
3475 			if (np == NONODEPROTO) return(HIGHLIGHTOBJ);
3476 		}
3477 	}
3478 	return(var->addr);
3479 }
3480 
3481 /*
3482  * Routine called when cell "np" has been deleted (and it may be a layer cell because its name
3483  * started with "layer-").
3484  */
us_teceddeletelayercell(NODEPROTO * np)3485 void us_teceddeletelayercell(NODEPROTO *np)
3486 {
3487 	REGISTER VARIABLE *var;
3488 	REGISTER NODEPROTO *onp;
3489 	REGISTER NODEINST *ni;
3490 	REGISTER BOOLEAN warned, isnode;
3491 	REGISTER CHAR *layername;
3492 	static INTBIG edtec_layer_key = 0;
3493 	REGISTER void *infstr;
3494 
3495 	/* may have deleted layer cell in technology library */
3496 	if (edtec_layer_key == 0) edtec_layer_key = makekey(x_("EDTEC_layer"));
3497 	layername = &np->protoname[6];
3498 	warned = FALSE;
3499 	for(onp = np->lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3500 	{
3501 		if (namesamen(onp->protoname, x_("node-"), 5) == 0) isnode = TRUE; else
3502 			if (namesamen(onp->protoname, x_("arc-"), 4) == 0) isnode = FALSE; else
3503 				continue;
3504 		for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3505 		{
3506 			var = getvalkey((INTBIG)ni, VNODEINST, VNODEPROTO, edtec_layer_key);
3507 			if (var == NOVARIABLE) continue;
3508 			if ((NODEPROTO *)var->addr == np) break;
3509 		}
3510 		if (ni != NONODEINST)
3511 		{
3512 			if (warned) addtoinfstr(infstr, ','); else
3513 			{
3514 				infstr = initinfstr();
3515 				formatinfstr(infstr, _("Warning: layer %s is used in"), layername);
3516 				warned = TRUE;
3517 			}
3518 			if (isnode) formatinfstr(infstr, _(" node %s"), &onp->protoname[5]); else
3519 				formatinfstr(infstr, _(" arc %s"), &onp->protoname[4]);
3520 		}
3521 	}
3522 	if (warned)
3523 		ttyputmsg(x_("%s"), returninfstr(infstr));
3524 
3525 	/* see if this layer is mentioned in the design rules */
3526 	us_tecedrenamecell(np->protoname, x_(""));
3527 }
3528 
3529 /*
3530  * Routine called when cell "np" has been deleted (and it may be a node cell because its name
3531  * started with "node-").
3532  */
us_teceddeletenodecell(NODEPROTO * np)3533 void us_teceddeletenodecell(NODEPROTO *np)
3534 {
3535 	/* see if this node is mentioned in the design rules */
3536 	us_tecedrenamecell(np->protoname, x_(""));
3537 }
3538 
3539 /******************** SUPPORT FOR "usredtecp.c" ROUTINES ********************/
3540 
3541 /*
3542  * routine to return the actual bounding box of layer node "ni" in the
3543  * reference variables "lx", "hx", "ly", and "hy"
3544  */
us_tecedgetbbox(NODEINST * ni,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)3545 void us_tecedgetbbox(NODEINST *ni, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
3546 {
3547 	REGISTER INTBIG twolambda;
3548 
3549 	*lx = ni->geom->lowx;
3550 	*hx = ni->geom->highx;
3551 	*ly = ni->geom->lowy;
3552 	*hy = ni->geom->highy;
3553 	if (ni->proto != gen_portprim) return;
3554 	twolambda = lambdaofnode(ni) * 2;
3555 	*lx += twolambda;   *hx -= twolambda;
3556 	*ly += twolambda;   *hy -= twolambda;
3557 }
3558 
us_tecedpointout(NODEINST * ni,NODEPROTO * np)3559 void us_tecedpointout(NODEINST *ni, NODEPROTO *np)
3560 {
3561 	REGISTER WINDOWPART *w;
3562 	CHAR *newpar[2];
3563 
3564 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3565 		if (w->curnodeproto == np) break;
3566 	if (w == NOWINDOWPART)
3567 	{
3568 		newpar[0] = describenodeproto(np);
3569 		us_editcell(1, newpar);
3570 	}
3571 	if (ni != NONODEINST)
3572 	{
3573 		us_clearhighlightcount();
3574 		(void)asktool(us_tool, x_("show-object"), (INTBIG)ni->geom);
3575 	}
3576 }
3577 
3578 /*
3579  * routine to swap entries "p1" and "p2" of the port list in "tlist"
3580  */
us_tecedswapports(INTBIG * p1,INTBIG * p2,TECH_NODES * tlist)3581 void us_tecedswapports(INTBIG *p1, INTBIG *p2, TECH_NODES *tlist)
3582 {
3583 	REGISTER INTBIG temp, *templ;
3584 	REGISTER CHAR *tempc;
3585 
3586 	templ = tlist->portlist[*p1].portarcs;
3587 	tlist->portlist[*p1].portarcs = tlist->portlist[*p2].portarcs;
3588 	tlist->portlist[*p2].portarcs = templ;
3589 
3590 	tempc = tlist->portlist[*p1].protoname;
3591 	tlist->portlist[*p1].protoname = tlist->portlist[*p2].protoname;
3592 	tlist->portlist[*p2].protoname = tempc;
3593 
3594 	temp = tlist->portlist[*p1].initialbits;
3595 	tlist->portlist[*p1].initialbits = tlist->portlist[*p2].initialbits;
3596 	tlist->portlist[*p2].initialbits = temp;
3597 
3598 	temp = tlist->portlist[*p1].lowxmul;
3599 	tlist->portlist[*p1].lowxmul = tlist->portlist[*p2].lowxmul;
3600 	tlist->portlist[*p2].lowxmul = (INTSML)temp;
3601 	temp = tlist->portlist[*p1].lowxsum;
3602 	tlist->portlist[*p1].lowxsum = tlist->portlist[*p2].lowxsum;
3603 	tlist->portlist[*p2].lowxsum = (INTSML)temp;
3604 
3605 	temp = tlist->portlist[*p1].lowymul;
3606 	tlist->portlist[*p1].lowymul = tlist->portlist[*p2].lowymul;
3607 	tlist->portlist[*p2].lowymul = (INTSML)temp;
3608 	temp = tlist->portlist[*p1].lowysum;
3609 	tlist->portlist[*p1].lowysum = tlist->portlist[*p2].lowysum;
3610 	tlist->portlist[*p2].lowysum = (INTSML)temp;
3611 
3612 	temp = tlist->portlist[*p1].highxmul;
3613 	tlist->portlist[*p1].highxmul = tlist->portlist[*p2].highxmul;
3614 	tlist->portlist[*p2].highxmul = (INTSML)temp;
3615 	temp = tlist->portlist[*p1].highxsum;
3616 	tlist->portlist[*p1].highxsum = tlist->portlist[*p2].highxsum;
3617 	tlist->portlist[*p2].highxsum = (INTSML)temp;
3618 
3619 	temp = tlist->portlist[*p1].highymul;
3620 	tlist->portlist[*p1].highymul = tlist->portlist[*p2].highymul;
3621 	tlist->portlist[*p2].highymul = (INTSML)temp;
3622 	temp = tlist->portlist[*p1].highysum;
3623 	tlist->portlist[*p1].highysum = tlist->portlist[*p2].highysum;
3624 	tlist->portlist[*p2].highysum = (INTSML)temp;
3625 
3626 	/* finally, swap the actual identifiers */
3627 	temp = *p1;   *p1 = *p2;   *p2 = temp;
3628 }
3629 
us_tecedsamplename(NODEPROTO * layernp)3630 CHAR *us_tecedsamplename(NODEPROTO *layernp)
3631 {
3632 	if (layernp == gen_portprim) return(x_("PORT"));
3633 	if (layernp == gen_cellcenterprim) return(x_("GRAB"));
3634 	if (layernp == NONODEPROTO) return(x_("HIGHLIGHT"));
3635 	return(&layernp->protoname[6]);
3636 }
3637 
3638 /* Technology Edit Reorder */
3639 static DIALOGITEM us_tecedredialogitems[] =
3640 {
3641  /*  1 */ {0, {376,208,400,288}, BUTTON, N_("OK")},
3642  /*  2 */ {0, {344,208,368,288}, BUTTON, N_("Cancel")},
3643  /*  3 */ {0, {28,4,404,200}, SCROLL, x_("")},
3644  /*  4 */ {0, {4,4,20,284}, MESSAGE, x_("")},
3645  /*  5 */ {0, {168,208,192,268}, BUTTON, N_("Up")},
3646  /*  6 */ {0, {212,208,236,268}, BUTTON, N_("Down")},
3647  /*  7 */ {0, {136,208,160,280}, BUTTON, N_("Far Up")},
3648  /*  8 */ {0, {244,208,268,280}, BUTTON, N_("Far Down")}
3649 };
3650 static DIALOG us_tecedredialog = {{75,75,488,373}, N_("Reorder Technology Primitives"), 0, 8, us_tecedredialogitems, 0, 0};
3651 
3652 /* special items for the "Reorder Primitives" dialog: */
3653 #define DTER_LIST           3		/* List of primitives (scroll) */
3654 #define DTER_TITLE          4		/* Primitive title (message) */
3655 #define DTER_UP             5		/* Move Up (button) */
3656 #define DTER_DOWN           6		/* Move Down (button) */
3657 #define DTER_FARUP          7		/* Move Far Up (button) */
3658 #define DTER_FARDOWN        8		/* Move Far Down (button) */
3659 
us_reorderprimdlog(CHAR * type,CHAR * prefix,CHAR * varname)3660 void us_reorderprimdlog(CHAR *type, CHAR *prefix, CHAR *varname)
3661 {
3662 	REGISTER INTBIG itemHit, i, j, total, len, amt;
3663 	CHAR line[100], **seqname;
3664 	REGISTER BOOLEAN changed;
3665 	LIBRARY *thelib[1];
3666 	NODEPROTO **sequence, *np;
3667 	REGISTER void *dia;
3668 
3669 	dia = DiaInitDialog(&us_tecedredialog);
3670 	if (dia == 0) return;
3671 	DiaInitTextDialog(dia, DTER_LIST, DiaNullDlogList, DiaNullDlogItem,
3672 		DiaNullDlogDone, -1, SCSELMOUSE);
3673 	esnprintf(line, 100, _("%s in technology %s"), type, el_curlib->libname);
3674 	DiaSetText(dia, DTER_TITLE, line);
3675 	thelib[0] = el_curlib;
3676 	total = us_teceditfindsequence(thelib, 1, prefix, varname, &sequence);
3677 	len = strlen(prefix);
3678 	for(i=0; i<total; i++)
3679 		DiaStuffLine(dia, DTER_LIST, &sequence[i]->protoname[len]);
3680 	DiaSelectLine(dia, DTER_LIST, 0);
3681 
3682 	changed = FALSE;
3683 	for(;;)
3684 	{
3685 		itemHit = DiaNextHit(dia);
3686 		if (itemHit == OK || itemHit == CANCEL) break;
3687 		if (itemHit == DTER_UP || itemHit == DTER_FARUP)
3688 		{
3689 			/* shift up */
3690 			if (itemHit == DTER_UP) amt = 1; else amt = 10;
3691 			for(j=0; j<amt; j++)
3692 			{
3693 				i = DiaGetCurLine(dia, DTER_LIST);
3694 				if (i <= 0) break;
3695 				np = sequence[i];
3696 				sequence[i] = sequence[i-1];
3697 				sequence[i-1] = np;
3698 				DiaSetScrollLine(dia, DTER_LIST, i, &sequence[i]->protoname[len]);
3699 				DiaSetScrollLine(dia, DTER_LIST, i-1, &sequence[i-1]->protoname[len]);
3700 			}
3701 			changed = TRUE;
3702 			continue;
3703 		}
3704 		if (itemHit == DTER_DOWN || itemHit == DTER_FARDOWN)
3705 		{
3706 			/* shift down */
3707 			if (itemHit == DTER_DOWN) amt = 1; else amt = 10;
3708 			for(j=0; j<amt; j++)
3709 			{
3710 				i = DiaGetCurLine(dia, DTER_LIST);
3711 				if (i >= total-1) continue;
3712 				np = sequence[i];
3713 				sequence[i] = sequence[i+1];
3714 				sequence[i+1] = np;
3715 				DiaSetScrollLine(dia, DTER_LIST, i, &sequence[i]->protoname[len]);
3716 				DiaSetScrollLine(dia, DTER_LIST, i+1, &sequence[i+1]->protoname[len]);
3717 			}
3718 			changed = TRUE;
3719 			continue;
3720 		}
3721 	}
3722 
3723 	/* preserve order */
3724 	if (itemHit == OK && changed)
3725 	{
3726 		seqname = (CHAR **)emalloc(total * (sizeof (CHAR *)), el_tempcluster);
3727 		for(i=0; i<total; i++)
3728 			seqname[i] = &sequence[i]->protoname[len];
3729 		setval((INTBIG)el_curlib, VLIBRARY, varname, (INTBIG)seqname,
3730 			VSTRING|VISARRAY|(total<<VLENGTHSH));
3731 		efree((CHAR *)seqname);
3732 	}
3733 	efree((CHAR *)sequence);
3734 	DiaDoneDialog(dia);
3735 }
3736