1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usredtecg.c
6  * User interface technology editor: conversion from technology to library
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "egraphics.h"
34 #include "efunction.h"
35 #include "tech.h"
36 #include "tecgen.h"
37 #include "tecart.h"
38 #include "usr.h"
39 #include "drc.h"
40 #include "usredtec.h"
41 
42 SPECIALTEXTDESCR us_tecedmisctexttable[] =
43 {
44 	{NONODEINST, 0, 0, 6000, TECHLAMBDA},
45 	{NONODEINST, 0, 0,    0, TECHDESCRIPT},
46 	{NONODEINST, 0, 0, 0, 0},
47 };
48 
49 SPECIALTEXTDESCR us_tecedlayertexttable[] =
50 {
51 	{NONODEINST, 0, 28000,  18000, LAYERSTYLE},
52 	{NONODEINST, 0, 28000,  12000, LAYERCIF},
53 	{NONODEINST, 0, 28000,   6000, LAYERDXF},
54 	{NONODEINST, 0, 28000,      0, LAYERGDS},
55 	{NONODEINST, 0, 28000,  -6000, LAYERFUNCTION},
56 	{NONODEINST, 0, 28000, -12000, LAYERLETTERS},
57 	{NONODEINST, 0, 28000, -18000, LAYERSPIRES},
58 	{NONODEINST, 0, 28000, -24000, LAYERSPICAP},
59 	{NONODEINST, 0, 28000, -30000, LAYERSPIECAP},
60 	{NONODEINST, 0, 28000, -36000, LAYER3DHEIGHT},
61 	{NONODEINST, 0, 28000, -42000, LAYER3DTHICK},
62 	{NONODEINST, 0, 28000, -48000, LAYERPRINTCOL},
63 	{NONODEINST, 0, 0, 0, 0},
64 };
65 
66 SPECIALTEXTDESCR us_tecedarctexttable[] =
67 {
68 	{NONODEINST, 0, 0, 30000, ARCFUNCTION},
69 	{NONODEINST, 0, 0, 24000, ARCFIXANG},
70 	{NONODEINST, 0, 0, 18000, ARCWIPESPINS},
71 	{NONODEINST, 0, 0, 12000, ARCNOEXTEND},
72 	{NONODEINST, 0, 0,  6000, ARCINC},
73 	{NONODEINST, 0, 0, 0, 0},
74 };
75 
76 SPECIALTEXTDESCR us_tecednodetexttable[] =
77 {
78 	{NONODEINST, 0, 0, 36000, NODEFUNCTION},
79 	{NONODEINST, 0, 0, 30000, NODESERPENTINE},
80 	{NONODEINST, 0, 0, 24000, NODESQUARE},
81 	{NONODEINST, 0, 0, 18000, NODEWIPES},
82 	{NONODEINST, 0, 0, 12000, NODELOCKABLE},
83 	{NONODEINST, 0, 0,  6000, NODEMULTICUT},
84 	{NONODEINST, 0, 0, 0, 0},
85 };
86 
87 /* prototypes for local routines */
88 static NODEINST *us_tecedplacegeom(POLYGON*, NODEPROTO*);
89 static void      us_tecedsetlist(NODEINST*, POLYGON*, INTBIG, INTBIG, INTBIG, INTBIG);
90 static void      us_tecedcreatespecialtext(NODEPROTO *np, SPECIALTEXTDESCR *table);
91 
92 /*
93  * convert technology "tech" into a library and return that library.
94  * Returns NOLIBRARY on error
95  */
us_tecedmakelibfromtech(TECHNOLOGY * tech)96 LIBRARY *us_tecedmakelibfromtech(TECHNOLOGY *tech)
97 {
98 	REGISTER CHAR *lay, *dxf, **sequence, **varnames, *fname, *gds;
99 	REGISTER INTBIG i, j, k, e, xs, ys, oldlam, *newmap, *mapptr, *minnodesize,
100 		tcon, func, nodexpos, bits, layertotal, arctotal, nodetotal, multicutsep,
101 		height3d, thick3d, lambda, min2x, min2y, nlx, nhx, nly, nhy, wid, xoff,
102 		*printcolors, *colors;
103 	INTBIG lx, hx, ly, hy, xpos[4], ypos[4], xsc[4], ysc[4], lxo, hxo, lyo, hyo,
104 		lxp, hxp, lyp, hyp, blx, bhx, bly, bhy;
105 	REGISTER BOOLEAN serp, square, wipes, lockable, first;
106 	float spires, spicap, spiecap;
107 	CHAR gdsbuf[50];
108 	REGISTER void *infstr;
109 	REGISTER NODEPROTO *np, **nplist, *pnp, **aplist;
110 	REGISTER VARIABLE *var, *var2, *var3, *var5, *var6, *var7, *var8,
111 		*var10, *var11, *varred, *vargreen, *varblue;
112 	REGISTER LIBRARY *lib;
113 	REGISTER NODEINST *ni, *oni, *nni;
114 	REGISTER ARCINST *ai;
115 	REGISTER PORTPROTO *pp, *opp;
116 	REGISTER ARCPROTO *ap;
117 	REGISTER GRAPHICS *desc;
118 	static POLYGON *poly = NOPOLYGON;
119 	REGISTER DRCRULES *rules;
120 	REGISTER TECH_POLYGON *ll;
121 	REGISTER TECH_NODES *techn;
122 	REGISTER TECH_COLORMAP *colmap;
123 	NODEINST node;
124 	ARCINST arc;
125 
126 	/* make sure network tool is on */
127 	if ((net_tool->toolstate&TOOLON) == 0)
128 	{
129 		ttyputerr(_("Network tool must be running...turning it on"));
130 		toolturnon(net_tool);
131 		ttyputerr(_("...now reissue the technology editing command"));
132 		return(NOLIBRARY);
133 	}
134 
135 	/* get polygon */
136 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
137 
138 	lib = newlibrary(tech->techname, tech->techname);
139 	if (lib == NOLIBRARY)
140 	{
141 		ttyputerr(_("Cannot create library %s"), tech->techname);
142 		return(NOLIBRARY);
143 	}
144 	ttyputmsg(_("Created library %s..."), tech->techname);
145 
146 	/* create the information node */
147 	np = newnodeproto(x_("factors"), lib);
148 	if (np == NONODEPROTO) return(NOLIBRARY);
149 	np->userbits |= TECEDITCELL;
150 
151 	/* modify this technology's lambda value to match the current one */
152 	oldlam = lib->lambda[tech->techindex];
153 	lambda = lib->lambda[art_tech->techindex];
154 	lib->lambda[tech->techindex] = lambda;
155 
156 	/* create the miscellaneous info cell (called "factors") */
157 	us_tecedmakeinfo(np, oldlam, tech->techdescript);
158 
159 	/* copy any miscellaneous variables and make a list of their names */
160 	j = 0;
161 	for(i=0; us_knownvars[i].varname != 0; i++)
162 	{
163 		us_knownvars[i].ival = 0;
164 		var = getval((INTBIG)tech, VTECHNOLOGY, -1, us_knownvars[i].varname);
165 		if (var == NOVARIABLE) continue;
166 		us_knownvars[i].ival = 1;
167 		j++;
168 		(void)setval((INTBIG)lib, VLIBRARY, us_knownvars[i].varname, var->addr, var->type);
169 	}
170 	if (j > 0)
171 	{
172 		varnames = (CHAR **)emalloc(j * (sizeof (CHAR *)), el_tempcluster);
173 		if (varnames == 0) return(NOLIBRARY);
174 		j = 0;
175 		for(i=0; us_knownvars[i].varname != 0; i++)
176 			if (us_knownvars[i].ival != 0) varnames[j++] = us_knownvars[i].varname;
177 		(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_variable_list"), (INTBIG)varnames,
178 			VSTRING|VISARRAY|(j<<VLENGTHSH));
179 		efree((CHAR *)varnames);
180 	}
181 
182 	/* create the layer node names */
183 	layertotal = tech->layercount;
184 	nplist = (NODEPROTO **)emalloc((layertotal * (sizeof (NODEPROTO *))), el_tempcluster);
185 	if (nplist == 0) return(NOLIBRARY);
186 
187 	/* create the layer nodes */
188 	ttyputmsg(_("Creating the layers..."));
189 	var2 = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("IO_cif_layer_names"));
190 	var3 = getval((INTBIG)tech, VTECHNOLOGY, -1, x_("IO_gds_layer_numbers"));
191 	var8 = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("IO_dxf_layer_names"));
192 	var5 = getval((INTBIG)tech, VTECHNOLOGY, VFLOAT|VISARRAY, x_("SIM_spice_resistance"));
193 	var6 = getval((INTBIG)tech, VTECHNOLOGY, VFLOAT|VISARRAY, x_("SIM_spice_capacitance"));
194 	var7 = getval((INTBIG)tech, VTECHNOLOGY, VFLOAT|VISARRAY, x_("SIM_spice_edge_capacitance"));
195 	var10 = getval((INTBIG)tech, VTECHNOLOGY, VINTEGER|VISARRAY, x_("TECH_layer_3dheight"));
196 	var11 = getval((INTBIG)tech, VTECHNOLOGY, VINTEGER|VISARRAY, x_("TECH_layer_3dthickness"));
197 	printcolors = us_getprintcolors(tech);
198 	for(i=0; i<layertotal; i++)
199 	{
200 		desc = tech->layers[i];
201 		infstr = initinfstr();
202 		addstringtoinfstr(infstr, x_("layer-"));
203 		addstringtoinfstr(infstr, layername(tech, i));
204 		fname = returninfstr(infstr);
205 
206 		/* make sure the layer doesn't exist */
207 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
208 			if (namesame(fname, np->protoname) == 0)
209 		{
210 			ttyputerr(_("Warning: multiple layers named '%s'"), fname);
211 			break;
212 		}
213 
214 		np = newnodeproto(fname, lib);
215 		if (np == NONODEPROTO) return(NOLIBRARY);
216 		np->userbits |= TECEDITCELL;
217 		nplist[i] = np;
218 
219 		/* compute foreign file formats */
220 		if (var2 == NOVARIABLE) lay = x_(""); else
221 			lay = ((CHAR **)var2->addr)[i];
222 		gds = x_("");
223 		if (var3 != NOVARIABLE && (var3->type&VISARRAY) != 0)
224 		{
225 			if ((var3->type&VTYPE) == VSTRING) gds = ((CHAR **)var3->addr)[i]; else
226 			{
227 				j = ((INTBIG *)var3->addr)[i];
228 				if (j >= 0)
229 				{
230 					esnprintf(gdsbuf, 50, x_("%ld"), j);
231 					gds = gdsbuf;
232 				}
233 			}
234 		}
235 		if (var8 == NOVARIABLE) dxf = x_(""); else
236 			dxf = ((CHAR **)var8->addr)[i];
237 
238 		/* compute the SPICE information */
239 		if (var5 == NOVARIABLE) spires = 0.0; else
240 			spires = ((float *)var5->addr)[i];
241 		if (var6 == NOVARIABLE) spicap = 0.0; else
242 			spicap = ((float *)var6->addr)[i];
243 		if (var7 == NOVARIABLE) spiecap = 0.0; else
244 			spiecap = ((float *)var7->addr)[i];
245 
246 		/* compute the 3D information */
247 		if (var10 == NOVARIABLE) height3d = 0; else
248 			height3d = ((INTBIG *)var10->addr)[i];
249 		if (var11 == NOVARIABLE) thick3d = 0; else
250 			thick3d = ((INTBIG *)var11->addr)[i];
251 
252 		/* get the print colors */
253 		if (printcolors == 0) colors = 0; else
254 			colors = &printcolors[i*5];
255 
256 		/* build the layer cell */
257 		us_tecedmakelayer(np, desc->col, desc->raster,
258 			desc->colstyle&(NATURE|OUTLINEPAT), lay, layerfunction(tech, i),
259 				us_layerletters(tech, i), dxf, gds, spires, spicap, spiecap,
260 					height3d, thick3d, colors);
261 	}
262 
263 	/* save the layer sequence */
264 	sequence = (CHAR **)emalloc(layertotal * (sizeof (CHAR *)), el_tempcluster);
265 	if (sequence == 0) return(NOLIBRARY);
266 	i = 0;
267 	for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
268 		if (namesamen(np->protoname, x_("layer-"), 6) == 0)
269 			sequence[i++] = &np->protoname[6];
270 	(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_layersequence"), (INTBIG)sequence,
271 		VSTRING|VISARRAY|(layertotal<<VLENGTHSH));
272 	efree((CHAR *)sequence);
273 
274 	/* create the arc cells */
275 	ttyputmsg(_("Creating the arcs..."));
276 	arctotal = 0;
277 	for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
278 	{
279 		ap->temp1 = (INTBIG)NONODEPROTO;
280 		if ((ap->userbits&ANOTUSED) != 0) continue;
281 		infstr = initinfstr();
282 		addstringtoinfstr(infstr, x_("arc-"));
283 		addstringtoinfstr(infstr, ap->protoname);
284 		fname = returninfstr(infstr);
285 
286 		/* make sure the arc doesn't exist */
287 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
288 			if (namesame(fname, np->protoname) == 0)
289 		{
290 			ttyputerr(_("Warning: multiple arcs named '%s'"), fname);
291 			break;
292 		}
293 
294 		np = newnodeproto(fname, lib);
295 		if (np == NONODEPROTO) return(NOLIBRARY);
296 		np->userbits |= TECEDITCELL;
297 		ap->temp1 = (INTBIG)np;
298 		var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
299 		if (var != NOVARIABLE) bits = var->addr; else
300 			bits = ap->userbits;
301 		us_tecedmakearc(np, (ap->userbits&AFUNCTION)>>AFUNCTIONSH,
302 			bits&WANTFIXANG, ap->userbits&CANWIPE, bits&WANTNOEXTEND,
303 				(ap->userbits&AANGLEINC)>>AANGLEINCSH);
304 
305 		/* now create the arc layers */
306 		ai = &arc;   initdummyarc(ai);
307 		ai->proto = ap;
308 		ai->width = defaultarcwidth(ap);
309 		wid = ai->width - arcwidthoffset(ai);
310 		ai->end[0].xpos = wid*2;
311 		ai->end[0].ypos = 0;
312 		ai->end[1].xpos = -wid*2;
313 		ai->end[1].ypos = 0;
314 		ai->length = computedistance(ai->end[0].xpos, ai->end[0].ypos, ai->end[1].xpos, ai->end[1].ypos);
315 		j = arcpolys(ai, NOWINDOWPART);
316 		xoff = wid*2 + wid/2 + arcwidthoffset(ai)/2;
317 		for(i=0; i<j; i++)
318 		{
319 			shapearcpoly(ai, i, poly);
320 			if (poly->layer < 0) continue;
321 			desc = tech->layers[poly->layer];
322 			if (desc->bits == LAYERN) continue;
323 
324 			/* scale the arc geometry appropriately */
325 			for(k=0; k<poly->count; k++)
326 			{
327 				poly->xv[k] = muldiv(poly->xv[k] - xoff, lambda, oldlam) - 40000;
328 				poly->yv[k] = muldiv(poly->yv[k], lambda, oldlam) - 10000;
329 			}
330 
331 			/* create the node to describe this layer */
332 			ni = us_tecedplacegeom(poly, np);
333 			if (ni == NONODEINST) continue;
334 
335 			/* get graphics for this layer */
336 			us_teceditsetpatch(ni, desc);
337 			(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"), (INTBIG)nplist[poly->layer], VNODEPROTO);
338 			(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
339 		}
340 		i = muldiv(arcwidthoffset(ai) / 2, lambda, oldlam);
341 		wid = muldiv(wid, lambda, oldlam);
342 		ni = newnodeinst(art_boxprim, -40000 - wid*5 - i, -40000-i,
343 			-10000-wid/2, -10000+wid/2, 0, 0, np);
344 		if (ni == NONODEINST) return(NOLIBRARY);
345 		(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, HIGHLIT, VINTEGER);
346 		(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"), (INTBIG)NONODEPROTO, VNODEPROTO);
347 		(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
348 		endobjectchange((INTBIG)ni, VNODEINST);
349 		arctotal++;
350 
351 		/* compact it accordingly */
352 		us_tecedcompact(np);
353 	}
354 
355 	/* save the arc sequence */
356 	sequence = (CHAR **)emalloc(arctotal * (sizeof (CHAR *)), el_tempcluster);
357 	if (sequence == 0) return(NOLIBRARY);
358 	i = 0;
359 	for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
360 	{
361 		if ((ap->userbits&ANOTUSED) != 0) continue;
362 		sequence[i++] = &((NODEPROTO *)ap->temp1)->protoname[4];
363 	}
364 	(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_arcsequence"), (INTBIG)sequence,
365 		VSTRING|VISARRAY|(arctotal<<VLENGTHSH));
366 	efree((CHAR *)sequence);
367 
368 	/* create the node cells */
369 	ttyputmsg(_("Creating the nodes..."));
370 	nodetotal = 0;
371 	for(pnp = tech->firstnodeproto; pnp != NONODEPROTO; pnp = pnp->nextnodeproto)
372 		if ((pnp->userbits&NNOTUSED) == 0) nodetotal++;
373 	minnodesize = (INTBIG *)emalloc(nodetotal*2*SIZEOFINTBIG, el_tempcluster);
374 	if (minnodesize == 0) return(NOLIBRARY);
375 	nodetotal = 0;
376 	for(pnp = tech->firstnodeproto; pnp != NONODEPROTO; pnp = pnp->nextnodeproto)
377 	{
378 		pnp->temp1 = 0;
379 		if ((pnp->userbits&NNOTUSED) != 0) continue;
380 		first = TRUE;
381 
382 		/* create the node layers */
383 		oni = &node;   initdummynode(oni);
384 		oni->proto = pnp;
385 		xs = (pnp->highx - pnp->lowx) * 2;
386 		ys = (pnp->highy - pnp->lowy) * 2;
387 		if (xs < 5000) xs = 5000;
388 		if (ys < 5000) ys = 5000;
389 		nodexpos = -xs*2;
390 		xpos[0] = nodexpos - xs;
391 		xpos[1] = nodexpos + xs;
392 		xpos[2] = nodexpos - xs;
393 		xpos[3] = nodexpos + xs;
394 		ypos[0] = -10000 + ys;
395 		ypos[1] = -10000 + ys;
396 		ypos[2] = -10000 - ys;
397 		ypos[3] = -10000 - ys;
398 		nodesizeoffset(oni, &lxp, &lyp, &hxp, &hyp);
399 		xs = (pnp->highx - pnp->lowx) - lxp - hxp;
400 		ys = (pnp->highy - pnp->lowy) - lyp - hyp;
401 		xsc[0] = xs*1;   ysc[0] = ys*1;
402 		xsc[1] = xs*2;   ysc[1] = ys*1;
403 		xsc[2] = xs*1;   ysc[2] = ys*2;
404 		xsc[3] = xs*2;   ysc[3] = ys*2;
405 
406 		/* for multicut contacts, make large size be just right for 2 cuts */
407 		techn = tech->nodeprotos[pnp->primindex-1];
408 		if (techn->special == MULTICUT)
409 		{
410 			min2x = (techn->f1*2 + techn->f3*2 + techn->f4) * oldlam / WHOLE;
411 			min2y = (techn->f2*2 + techn->f3*2 + techn->f4) * oldlam / WHOLE;
412 			xsc[1] = min2x;
413 			xsc[3] = min2x;
414 			ysc[2] = min2y;
415 			ysc[3] = min2y;
416 		}
417 		for(e=0; e<4; e++)
418 		{
419 			/* do not create node if main example had no polygons */
420 			if (e != 0 && first) continue;
421 
422 			/* square nodes have only two examples */
423 			if ((pnp->userbits&NSQUARE) != 0 && (e == 1 || e == 2)) continue;
424 			oni->lowx  = xpos[e] - xsc[e]/2 - lxp;
425 			oni->lowy  = ypos[e] - ysc[e]/2 - lyp;
426 			oni->highx = xpos[e] + xsc[e]/2 + hxp;
427 			oni->highy = ypos[e] + ysc[e]/2 + hyp;
428 
429 			/* place the layers */
430 			j = nodepolys(oni, 0, NOWINDOWPART);
431 			for(i=0; i<j; i++)
432 			{
433 				shapenodepoly(oni, i, poly);
434 				if (poly->layer < 0) continue;
435 				desc = tech->layers[poly->layer];
436 				if (desc->bits == LAYERN) continue;
437 
438 				for(k=0; k<poly->count; k++)
439 				{
440 					poly->xv[k] = poly->xv[k] * lambda / oldlam;
441 					poly->yv[k] = poly->yv[k] * lambda / oldlam;
442 				}
443 				/* accumulate total size of main example */
444 				if (e == 0)
445 				{
446 					getbbox(poly, &blx, &bhx, &bly, &bhy);
447 					if (i == 0)
448 					{
449 						nlx = blx;   nhx = bhx;
450 						nly = bly;   nhy = bhy;
451 					} else
452 					{
453 						if (blx < nlx) nlx = blx;
454 						if (bhx > nhx) nhx = bhx;
455 						if (bly < nly) nly = bly;
456 						if (bhy > nhy) nhy = bhy;
457 					}
458 				}
459 
460 				/* create the node cell on the first valid layer */
461 				if (first)
462 				{
463 					first = FALSE;
464 					infstr = initinfstr();
465 					addstringtoinfstr(infstr, x_("node-"));
466 					addstringtoinfstr(infstr, pnp->protoname);
467 					fname = returninfstr(infstr);
468 
469 					/* make sure the node doesn't exist */
470 					for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
471 						if (namesame(fname, np->protoname) == 0)
472 					{
473 						ttyputerr(_("Warning: multiple nodes named '%s'"), fname);
474 						break;
475 					}
476 
477 					np = newnodeproto(fname, lib);
478 					if (np == NONODEPROTO) return(NOLIBRARY);
479 					np->userbits |= TECEDITCELL;
480 					func = (pnp->userbits&NFUNCTION)>>NFUNCTIONSH;
481 					serp = FALSE;
482 					if ((func == NPTRANMOS || func == NPTRAPMOS || func == NPTRADMOS) &&
483 						(pnp->userbits&HOLDSTRACE) != 0)
484 							serp = TRUE;
485 					if ((pnp->userbits&NSQUARE) != 0) square = TRUE; else
486 						square = FALSE;
487 					if ((pnp->userbits&WIPEON1OR2) != 0) wipes = TRUE; else
488 						wipes = FALSE;
489 					if ((pnp->userbits&LOCKEDPRIM) != 0) lockable = TRUE; else
490 						lockable = FALSE;
491 					if (techn->special == MULTICUT) multicutsep = techn->f4; else
492 						multicutsep = 0;
493 					us_tecedmakenode(np, func, serp, square, wipes, lockable, multicutsep);
494 					pnp->temp1 = (INTBIG)np;
495 				}
496 
497 				/* create the node to describe this layer */
498 				ni = us_tecedplacegeom(poly, np);
499 				if (ni == NONODEINST) return(NOLIBRARY);
500 
501 				/* get graphics for this layer */
502 				us_teceditsetpatch(ni, desc);
503 				(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"),
504 					(INTBIG)nplist[poly->layer], VNODEPROTO);
505 				(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
506 
507 				/* set minimum polygon factor on smallest example */
508 				if (e != 0) continue;
509 				if (i >= tech->nodeprotos[pnp->primindex-1]->layercount) continue;
510 				ll = tech->nodeprotos[pnp->primindex-1]->layerlist;
511 				if (ll == 0) continue;
512 				if (ll[i].representation != MINBOX) continue;
513 				var = setval((INTBIG)ni, VNODEINST, x_("EDTEC_minbox"), (INTBIG)x_("MIN"), VSTRING|VDISPLAY);
514 				if (var != NOVARIABLE)
515 					defaulttextsize(3, var->textdescript);
516 			}
517 			if (first) continue;
518 
519 			/* create the highlight node */
520 			lx = (xpos[e]-xsc[e]/2) * lambda / oldlam;
521 			hx = (xpos[e]+xsc[e]/2) * lambda / oldlam;
522 			ly = (ypos[e]-ysc[e]/2) * lambda / oldlam;
523 			hy = (ypos[e]+ysc[e]/2) * lambda / oldlam;
524 			ni = newnodeinst(art_boxprim, lx, hx, ly, hy, 0, 0, np);
525 			if (ni == NONODEINST) return(NOLIBRARY);
526 			(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, HIGHLIT, VINTEGER);
527 			(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_layer"), (INTBIG)NONODEPROTO, VNODEPROTO);
528 			(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
529 			endobjectchange((INTBIG)ni, VNODEINST);
530 
531 			/* create a grab node (only in main example) */
532 			if (e == 0)
533 			{
534 				var = getvalkey((INTBIG)pnp, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
535 				if (var != NOVARIABLE)
536 				{
537 					lx = hx = xpos[0] + ((INTBIG *)var->addr)[0];
538 					ly = hy = ypos[0] + ((INTBIG *)var->addr)[1];
539 					lx = lx * lambda / oldlam;
540 					hx = hx * lambda / oldlam;
541 					ly = ly * lambda / oldlam;
542 					hy = hy * lambda / oldlam;
543 					nodeprotosizeoffset(gen_cellcenterprim, &lxo, &lyo, &hxo, &hyo, np);
544 					ni = newnodeinst(gen_cellcenterprim, lx-lxo, hx+hxo, ly-lyo, hy+hyo, 0, 0, np);
545 					if (ni == NONODEINST) return(NOLIBRARY);
546 					endobjectchange((INTBIG)ni, VNODEINST);
547 				}
548 			}
549 
550 			/* also draw ports */
551 			for(pp = pnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
552 			{
553 				shapeportpoly(oni, pp, poly, FALSE);
554 				getbbox(poly, &lx, &hx, &ly, &hy);
555 				lx = lx * lambda / oldlam;
556 				hx = hx * lambda / oldlam;
557 				ly = ly * lambda / oldlam;
558 				hy = hy * lambda / oldlam;
559 				nodeprotosizeoffset(gen_portprim, &lxo, &lyo, &hxo, &hyo, np);
560 				ni = newnodeinst(gen_portprim, lx-lxo, hx+hxo, ly-lyo, hy+hyo, 0, 0, np);
561 				if (ni == NONODEINST) return(NOLIBRARY);
562 				pp->temp1 = (INTBIG)ni;
563 				(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCH, VINTEGER);
564 				var = setval((INTBIG)ni, VNODEINST, x_("EDTEC_portname"), (INTBIG)pp->protoname,
565 					VSTRING|VDISPLAY);
566 				if (var != NOVARIABLE)
567 					defaulttextsize(3, var->textdescript);
568 				endobjectchange((INTBIG)ni, VNODEINST);
569 
570 				/* on the first sample, also show angle and connection */
571 				if (e != 0) continue;
572 				if (((pp->userbits&PORTANGLE)>>PORTANGLESH) != 0 ||
573 					((pp->userbits&PORTARANGE)>>PORTARANGESH) != 180)
574 				{
575 					(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_portangle"),
576 						(pp->userbits&PORTANGLE)>>PORTANGLESH, VINTEGER);
577 					(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_portrange"),
578 						(pp->userbits&PORTARANGE)>>PORTARANGESH, VINTEGER);
579 				}
580 
581 				/* add in the "local" port connections (from this tech) */
582 				for(tcon=i=0; pp->connects[i] != NOARCPROTO; i++)
583 					if (pp->connects[i]->tech == tech) tcon++;
584 				if (tcon != 0)
585 				{
586 					aplist = (NODEPROTO **)emalloc((tcon * (sizeof (NODEPROTO *))), el_tempcluster);
587 					if (aplist == 0) return(NOLIBRARY);
588 					for(j=i=0; pp->connects[i] != NOARCPROTO; i++)
589 					{
590 						if (pp->connects[i]->tech != tech) continue;
591 						aplist[j] = (NODEPROTO *)pp->connects[i]->temp1;
592 						if (aplist[j] != NONODEPROTO) j++;
593 					}
594 					(void)setval((INTBIG)ni, VNODEINST, x_("EDTEC_connects"),
595 						(INTBIG)aplist, VNODEPROTO|VISARRAY|(j<<VLENGTHSH));
596 					efree((CHAR *)aplist);
597 				}
598 
599 				/* connect the connected ports */
600 				for(opp = pnp->firstportproto; opp != pp; opp = opp->nextportproto)
601 				{
602 					if (opp->network != pp->network) continue;
603 					nni = (NODEINST *)opp->temp1;
604 					if (nni == NONODEINST) continue;
605 					if (newarcinst(gen_universalarc, 0, 0, ni, ni->proto->firstportproto,
606 						(ni->highx+ni->lowx)/2, (ni->highy+ni->lowy)/2, nni,
607 							nni->proto->firstportproto, (nni->highx+nni->lowx)/2,
608 								(nni->highy+nni->lowy)/2, np) == NOARCINST) return(NOLIBRARY);
609 					break;
610 				}
611 			}
612 		}
613 		minnodesize[nodetotal*2] = (nhx - nlx) * WHOLE / lambda;
614 		minnodesize[nodetotal*2+1] = (nhy - nly) * WHOLE / lambda;
615 		nodetotal++;
616 
617 		/* compact it accordingly */
618 		us_tecedcompact(np);
619 	}
620 
621 	/* save the node sequence */
622 	sequence = (CHAR **)emalloc(nodetotal * (sizeof (CHAR *)), el_tempcluster);
623 	if (sequence == 0) return(NOLIBRARY);
624 	i = 0;
625 	for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
626 		if (np->temp1 != 0)
627 			sequence[i++] = &((NODEPROTO *)np->temp1)->protoname[5];
628 	(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_nodesequence"), (INTBIG)sequence,
629 		VSTRING|VISARRAY|(i<<VLENGTHSH));
630 	efree((CHAR *)sequence);
631 
632 	/* create the color map information */
633 	ttyputmsg(_("Adding color map and design rules..."));
634 	var2 = getval((INTBIG)tech, VTECHNOLOGY, VCHAR|VISARRAY, x_("USER_color_map"));
635 	varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
636 	vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
637 	varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
638 	if (varred != NOVARIABLE && vargreen != NOVARIABLE && varblue != NOVARIABLE &&
639 		var2 != NOVARIABLE)
640 	{
641 		newmap = emalloc((256*3*SIZEOFINTBIG), el_tempcluster);
642 		if (newmap == 0) return(NOLIBRARY);
643 		mapptr = newmap;
644 		colmap = (TECH_COLORMAP *)var2->addr;
645 		for(i=0; i<256; i++)
646 		{
647 			*mapptr++ = ((INTBIG *)varred->addr)[i];
648 			*mapptr++ = ((INTBIG *)vargreen->addr)[i];
649 			*mapptr++ = ((INTBIG *)varblue->addr)[i];
650 		}
651 		for(i=0; i<32; i++)
652 		{
653 			newmap[(i<<2)*3]   = colmap[i].red;
654 			newmap[(i<<2)*3+1] = colmap[i].green;
655 			newmap[(i<<2)*3+2] = colmap[i].blue;
656 		}
657 		(void)setval((INTBIG)lib, VLIBRARY, x_("EDTEC_colormap"), (INTBIG)newmap,
658 			VINTEGER|VISARRAY|((256*3)<<VLENGTHSH));
659 		efree((CHAR *)newmap);
660 	}
661 
662 	/* create the design rule information */
663 	rules = dr_allocaterules(layertotal, nodetotal, tech->techname);
664 	if (rules == NODRCRULES) return(NOLIBRARY);
665 	for(i=0; i<layertotal; i++)
666 		(void)allocstring(&rules->layernames[i], layername(tech, i), el_tempcluster);
667 	i = 0;
668 	for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
669 		if (np->temp1 != 0)
670 			(void)allocstring(&rules->nodenames[i++],  &((NODEPROTO *)np->temp1)->protoname[5],
671 				el_tempcluster);
672 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_min_widthkey);
673 	if (var != NOVARIABLE)
674 		for(i=0; i<rules->numlayers; i++) rules->minwidth[i] = ((INTBIG *)var->addr)[i];
675 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_min_width_rulekey);
676 	if (var != NOVARIABLE)
677 		for(i=0; i<rules->numlayers; i++)
678 			(void)reallocstring(&rules->minwidthR[i], ((CHAR **)var->addr)[i], el_tempcluster);
679 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distanceskey);
680 	if (var != NOVARIABLE)
681 		for(i=0; i<rules->utsize; i++) rules->conlist[i] = ((INTBIG *)var->addr)[i];
682 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distances_rulekey);
683 	if (var != NOVARIABLE)
684 		for(i=0; i<rules->utsize; i++)
685 			(void)reallocstring(&rules->conlistR[i], ((CHAR **)var->addr)[i], el_tempcluster);
686 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distanceskey);
687 	if (var != NOVARIABLE)
688 		for(i=0; i<rules->utsize; i++) rules->unconlist[i] = ((INTBIG *)var->addr)[i];
689 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distances_rulekey);
690 	if (var != NOVARIABLE)
691 		for(i=0; i<rules->utsize; i++)
692 			(void)reallocstring(&rules->unconlistR[i], ((CHAR **)var->addr)[i], el_tempcluster);
693 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distancesWkey);
694 	if (var != NOVARIABLE)
695 		for(i=0; i<rules->utsize; i++) rules->conlistW[i] = ((INTBIG *)var->addr)[i];
696 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distancesW_rulekey);
697 	if (var != NOVARIABLE)
698 		for(i=0; i<rules->utsize; i++)
699 			(void)reallocstring(&rules->conlistWR[i], ((CHAR **)var->addr)[i], el_tempcluster);
700 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distancesWkey);
701 	if (var != NOVARIABLE)
702 		for(i=0; i<rules->utsize; i++) rules->unconlistW[i] = ((INTBIG *)var->addr)[i];
703 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distancesW_rulekey);
704 	if (var != NOVARIABLE)
705 		for(i=0; i<rules->utsize; i++)
706 			(void)reallocstring(&rules->unconlistWR[i], ((CHAR **)var->addr)[i], el_tempcluster);
707 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_connected_distancesMkey);
708 	if (var != NOVARIABLE)
709 		for(i=0; i<rules->utsize; i++) rules->conlistM[i] = ((INTBIG *)var->addr)[i];
710 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_connected_distancesM_rulekey);
711 	if (var != NOVARIABLE)
712 		for(i=0; i<rules->utsize; i++)
713 			(void)reallocstring(&rules->conlistMR[i], ((CHAR **)var->addr)[i], el_tempcluster);
714 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_unconnected_distancesMkey);
715 	if (var != NOVARIABLE)
716 		for(i=0; i<rules->utsize; i++) rules->unconlistM[i] = ((INTBIG *)var->addr)[i];
717 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_unconnected_distancesM_rulekey);
718 	if (var != NOVARIABLE)
719 		for(i=0; i<rules->utsize; i++)
720 			(void)reallocstring(&rules->unconlistMR[i], ((CHAR **)var->addr)[i], el_tempcluster);
721 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_edge_distanceskey);
722 	if (var != NOVARIABLE)
723 		for(i=0; i<rules->utsize; i++) rules->edgelist[i] = ((INTBIG *)var->addr)[i];
724 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_edge_distances_rulekey);
725 	if (var != NOVARIABLE)
726 		for(i=0; i<rules->utsize; i++)
727 			(void)reallocstring(&rules->edgelistR[i], ((CHAR **)var->addr)[i], el_tempcluster);
728 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT, dr_wide_limitkey);
729 	if (var != NOVARIABLE) rules->widelimit = var->addr;
730 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VFRACT|VISARRAY, dr_min_node_sizekey);
731 	if (var != NOVARIABLE)
732 	{
733 		i = j = 0;
734 		for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
735 		{
736 			if (np->temp1 != 0)
737 			{
738 				rules->minnodesize[i*2] = ((INTBIG *)var->addr)[j*2];
739 				rules->minnodesize[i*2+1] = ((INTBIG *)var->addr)[j*2+1];
740 
741 				/* if rule is valid, make sure it is no larger than actual size */
742 				if (rules->minnodesize[i*2] > 0 && rules->minnodesize[i*2+1] > 0)
743 				{
744 					if (rules->minnodesize[i*2] > minnodesize[i*2])
745 						rules->minnodesize[i*2] = minnodesize[i*2];
746 					if (rules->minnodesize[i*2+1] > minnodesize[i*2+1])
747 						rules->minnodesize[i*2+1] = minnodesize[i*2+1];
748 				}
749 				i++;
750 			}
751 			j++;
752 		}
753 	}
754 	var = getvalkey((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, dr_min_node_size_rulekey);
755 	if (var != NOVARIABLE)
756 	{
757 		i = j = 0;
758 		for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
759 		{
760 			if (np->temp1 != 0)
761 			{
762 				reallocstring(&rules->minnodesizeR[i], ((CHAR **)var->addr)[j], el_tempcluster);
763 				i++;
764 			}
765 			j++;
766 		}
767 	}
768 
769 	us_tecedloaddrcmessage(rules, lib);
770 	dr_freerules(rules);
771 
772 	/* clean up */
773 	ttyputmsg(_("Done."));
774 	efree((CHAR *)nplist);
775 	efree((CHAR *)minnodesize);
776 	lib->lambda[tech->techindex] = oldlam;
777 	return(lib);
778 }
779 
780 /*************************** CELL CREATION HELPERS ***************************/
781 
782 /*
783  * routine to build the appropriate descriptive information for the information
784  * cell "np".
785  */
us_tecedmakeinfo(NODEPROTO * np,INTBIG lambda,CHAR * description)786 void us_tecedmakeinfo(NODEPROTO *np, INTBIG lambda, CHAR *description)
787 {
788 	REGISTER INTBIG i;
789 
790 	/* load up the structure with the current values */
791 	for(i=0; us_tecedmisctexttable[i].funct != 0; i++)
792 	{
793 		switch (us_tecedmisctexttable[i].funct)
794 		{
795 			case TECHLAMBDA:
796 				us_tecedmisctexttable[i].value = (void *)lambda;
797 				break;
798 			case TECHDESCRIPT:
799 				us_tecedmisctexttable[i].value = (void *)description;
800 				break;
801 		}
802 	}
803 
804 	/* now create those text objects */
805 	us_tecedcreatespecialtext(np, us_tecedmisctexttable);
806 }
807 
808 /*
809  * routine to build the appropriate descriptive information for a layer into
810  * cell "np".  The color is "colorindex"; the stipple array is in "stip"; the
811  * layer style is in "style", the CIF layer is in "ciflayer"; the function is
812  * in "functionindex"; the layer letters are in "layerletters"; the DXF layer name(s)
813  * are "dxf"; the Calma GDS-II layer is in "gds"; the SPICE resistance is in "spires",
814  * the SPICE capacitance is in "spicap", the SPICE edge capacitance is in "spiecap",
815  * the 3D height is in "height3d", and the 3D thickness is in "thick3d".
816  */
us_tecedmakelayer(NODEPROTO * np,INTBIG colorindex,UINTSML stip[16],INTBIG style,CHAR * ciflayer,INTBIG functionindex,CHAR * layerletters,CHAR * dxf,CHAR * gds,float spires,float spicap,float spiecap,INTBIG height3d,INTBIG thick3d,INTBIG * printcolors)817 void us_tecedmakelayer(NODEPROTO *np, INTBIG colorindex, UINTSML stip[16], INTBIG style,
818 	CHAR *ciflayer, INTBIG functionindex, CHAR *layerletters, CHAR *dxf,
819 	CHAR *gds, float spires, float spicap, float spiecap,
820 	INTBIG height3d, INTBIG thick3d, INTBIG *printcolors)
821 {
822 	REGISTER NODEINST *nicolor, *ni, *laypatcontrol, *laycolor, *laystipple;
823 	REGISTER INTBIG i, x, y;
824 	REGISTER VARIABLE *var;
825 	CHAR *colorname, *colorsymbol, *newname;
826 	UINTBIG pattern[16];
827 	UINTSML spattern[16];
828 	REGISTER void *infstr;
829 
830 	laycolor = laystipple = laypatcontrol = NONODEINST;
831 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
832 	{
833 		var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
834 		if (var == NOVARIABLE) continue;
835 		switch (var->addr)
836 		{
837 			case LAYERCOLOR:     laycolor = ni;      break;
838 			case LAYERPATTERN:   laystipple = ni;    break;
839 			case LAYERPATCONT:   laypatcontrol = ni; break;
840 		}
841 	}
842 
843 	/* create the color information if it is not there */
844 	if (laycolor == NONODEINST)
845 	{
846 		/* create the graphic color object */
847 		nicolor = newnodeinst(art_filledboxprim, -20000, -10000, 10000, 20000, 0, 0, np);
848 		if (nicolor == NONODEINST) return;
849 		(void)setvalkey((INTBIG)nicolor, VNODEINST, art_colorkey, colorindex, VINTEGER);
850 		(void)setval((INTBIG)np, VNODEPROTO, x_("EDTEC_colornode"), (INTBIG)nicolor, VNODEINST);
851 		if ((style&NATURE) == PATTERNED)
852 		{
853 			if ((style&OUTLINEPAT) == 0)
854 			{
855 				for(i=0; i<16; i++) pattern[i] = stip[i];
856 				(void)setvalkey((INTBIG)nicolor, VNODEINST, art_patternkey, (INTBIG)pattern,
857 					VINTEGER|VISARRAY|(16<<VLENGTHSH));
858 			} else
859 			{
860 				for(i=0; i<16; i++) spattern[i] = stip[i];
861 				(void)setvalkey((INTBIG)nicolor, VNODEINST, art_patternkey, (INTBIG)spattern,
862 					VSHORT|VISARRAY|(16<<VLENGTHSH));
863 			}
864 		}
865 		endobjectchange((INTBIG)nicolor, VNODEINST);
866 
867 		/* create the text color object */
868 		ni = newnodeinst(gen_invispinprim, 20000, 20000, 24000, 24000, 0, 0, np);
869 		if (ni == NONODEINST) return;
870 		infstr = initinfstr();
871 		addstringtoinfstr(infstr, TECEDNODETEXTCOLOR);
872 		if (ecolorname(colorindex, &colorname, &colorsymbol)) colorname = x_("unknown");
873 		addstringtoinfstr(infstr, colorname);
874 		allocstring(&newname, returninfstr(infstr), el_tempcluster);
875 		var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)newname,
876 			VSTRING|VDISPLAY);
877 		efree(newname);
878 		if (var != NOVARIABLE)
879 			defaulttextsize(2, var->textdescript);
880 		(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERCOLOR, VINTEGER);
881 		endobjectchange((INTBIG)ni, VNODEINST);
882 	}
883 
884 	/* create the stipple pattern objects if none are there */
885 	if (laystipple == NONODEINST)
886 	{
887 		for(x=0; x<16; x++) for(y=0; y<16; y++)
888 		{
889 			if ((stip[y] & (1 << (15-x))) != 0)
890 			{
891 				ni = newnodeinst(art_filledboxprim, x*2000-40000, x*2000-38000,
892 					4000-y*2000, 6000-y*2000, 0, 0, np);
893 			} else
894 			{
895 				ni = newnodeinst(art_filledboxprim, x*2000-40000, x*2000-38000, 4000-y*2000,
896 					6000-y*2000, 0, 0, np);
897 				for(i=0; i<16; i++) spattern[i] = 0;
898 				(void)setvalkey((INTBIG)ni, VNODEINST, art_patternkey, (INTBIG)spattern,
899 					VSHORT|VISARRAY|(16<<VLENGTHSH));
900 			}
901 			if (ni == NONODEINST) return;
902 			(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATTERN, VINTEGER);
903 			endobjectchange((INTBIG)ni, VNODEINST);
904 		}
905 		ni = newnodeinst(gen_invispinprim, -24000, -24000, 7000, 7000, 0, 0, np);
906 		if (ni == NONODEINST) return;
907 		var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)x_("Stipple Pattern"),
908 			VSTRING|VDISPLAY);
909 		if (var != NOVARIABLE)
910 			TDSETSIZE(var->textdescript, TXTSETQLAMBDA(2));
911 		endobjectchange((INTBIG)ni, VNODEINST);
912 	}
913 
914 	/* create the patch control object */
915 	if (laypatcontrol == NONODEINST)
916 	{
917 		ni = newnodeinst(gen_invispinprim, 16000-40000, 16000-40000, 4000-16*2000, 4000-16*2000, 0, 0, np);
918 		if (ni == NONODEINST) return;
919 		infstr = initinfstr();
920 		addstringtoinfstr(infstr, _("Stipple Pattern Operations"));
921 		allocstring(&newname, returninfstr(infstr), el_tempcluster);
922 		var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)newname, VSTRING|VDISPLAY);
923 		efree(newname);
924 		if (var != NOVARIABLE)
925 			defaulttextsize(2, var->textdescript);
926 		(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, LAYERPATCONT, VINTEGER);
927 		endobjectchange((INTBIG)ni, VNODEINST);
928 	}
929 
930 	/* load up the structure with the current values */
931 	for(i=0; us_tecedlayertexttable[i].funct != 0; i++)
932 	{
933 		switch (us_tecedlayertexttable[i].funct)
934 		{
935 			case LAYERSTYLE:
936 				us_tecedlayertexttable[i].value = (void *)style;
937 				break;
938 			case LAYERCIF:
939 				us_tecedlayertexttable[i].value = (void *)ciflayer;
940 				break;
941 			case LAYERDXF:
942 				us_tecedlayertexttable[i].value = (void *)dxf;
943 				break;
944 			case LAYERGDS:
945 				us_tecedlayertexttable[i].value = (void *)gds;
946 				break;
947 			case LAYERFUNCTION:
948 				us_tecedlayertexttable[i].value = (void *)functionindex;
949 				break;
950 			case LAYERLETTERS:
951 				us_tecedlayertexttable[i].value = (void *)layerletters;
952 				break;
953 			case LAYERSPIRES:
954 				us_tecedlayertexttable[i].value = (void *)castint(spires);
955 				break;
956 			case LAYERSPICAP:
957 				us_tecedlayertexttable[i].value = (void *)castint(spicap);
958 				break;
959 			case LAYERSPIECAP:
960 				us_tecedlayertexttable[i].value = (void *)castint(spiecap);
961 				break;
962 			case LAYER3DHEIGHT:
963 				us_tecedlayertexttable[i].value = (void *)height3d;
964 				break;
965 			case LAYER3DTHICK:
966 				us_tecedlayertexttable[i].value = (void *)thick3d;
967 				break;
968 			case LAYERPRINTCOL:
969 				us_tecedlayertexttable[i].value = (void *)printcolors;
970 				break;
971 		}
972 	}
973 
974 	/* now create those text objects */
975 	us_tecedcreatespecialtext(np, us_tecedlayertexttable);
976 }
977 
978 /*
979  * routine to build the appropriate descriptive information for an arc into
980  * cell "np".  The function is in "func"; the arc is fixed-angle if "fixang"
981  * is nonzero; the arc wipes pins if "wipes" is nonzero; and the arc does
982  * not extend its ends if "noextend" is nonzero.  The angle increment is
983  * in "anginc".
984  */
us_tecedmakearc(NODEPROTO * np,INTBIG func,INTBIG fixang,INTBIG wipes,INTBIG noextend,INTBIG anginc)985 void us_tecedmakearc(NODEPROTO *np, INTBIG func, INTBIG fixang, INTBIG wipes, INTBIG noextend,
986 	INTBIG anginc)
987 {
988 	REGISTER INTBIG i;
989 
990 	/* load up the structure with the current values */
991 	for(i=0; us_tecedarctexttable[i].funct != 0; i++)
992 	{
993 		switch (us_tecedarctexttable[i].funct)
994 		{
995 			case ARCFUNCTION:
996 				us_tecedarctexttable[i].value = (void *)func;
997 				break;
998 			case ARCFIXANG:
999 				us_tecedarctexttable[i].value = (void *)fixang;
1000 				break;
1001 			case ARCWIPESPINS:
1002 				us_tecedarctexttable[i].value = (void *)wipes;
1003 				break;
1004 			case ARCNOEXTEND:
1005 				us_tecedarctexttable[i].value = (void *)noextend;
1006 				break;
1007 			case ARCINC:
1008 				us_tecedarctexttable[i].value = (void *)anginc;
1009 				break;
1010 		}
1011 	}
1012 
1013 	/* now create those text objects */
1014 	us_tecedcreatespecialtext(np, us_tecedarctexttable);
1015 }
1016 
1017 /*
1018  * routine to build the appropriate descriptive information for a node into
1019  * cell "np".  The function is in "func", the serpentine transistor factor
1020  * is in "serp", the node is square if "square" is true, the node
1021  * is invisible on 1 or 2 arcs if "wipes" is true, and the node is lockable
1022  * if "lockable" is true.
1023  */
us_tecedmakenode(NODEPROTO * np,INTBIG func,BOOLEAN serp,BOOLEAN square,BOOLEAN wipes,BOOLEAN lockable,INTBIG multicutsep)1024 void us_tecedmakenode(NODEPROTO *np, INTBIG func, BOOLEAN serp, BOOLEAN square, BOOLEAN wipes,
1025 	BOOLEAN lockable, INTBIG multicutsep)
1026 {
1027 	REGISTER INTBIG i;
1028 
1029 	/* load up the structure with the current values */
1030 	for(i=0; us_tecednodetexttable[i].funct != 0; i++)
1031 	{
1032 		switch (us_tecednodetexttable[i].funct)
1033 		{
1034 			case NODEFUNCTION:
1035 				us_tecednodetexttable[i].value = (void *)func;
1036 				break;
1037 			case NODESERPENTINE:
1038 				us_tecednodetexttable[i].value = (void *)((INTBIG)serp);
1039 				break;
1040 			case NODESQUARE:
1041 				us_tecednodetexttable[i].value = (void *)((INTBIG)square);
1042 				break;
1043 			case NODEWIPES:
1044 				us_tecednodetexttable[i].value = (void *)((INTBIG)wipes);
1045 				break;
1046 			case NODELOCKABLE:
1047 				us_tecednodetexttable[i].value = (void *)((INTBIG)lockable);
1048 				break;
1049 			case NODEMULTICUT:
1050 				us_tecednodetexttable[i].value = (void *)multicutsep;
1051 				break;
1052 		}
1053 	}
1054 
1055 	/* now create those text objects */
1056 	us_tecedcreatespecialtext(np, us_tecednodetexttable);
1057 }
1058 
1059 /*
1060  * routine to add the text corresponding to the layer function in "func"
1061  * to the current infinite string
1062  */
us_tecedaddfunstring(void * infstr,INTBIG func)1063 void us_tecedaddfunstring(void *infstr, INTBIG func)
1064 {
1065 	REGISTER INTBIG i;
1066 
1067 	addstringtoinfstr(infstr, us_teclayer_functions[func&LFTYPE].name);
1068 	for(i=0; us_teclayer_functions[i].name != 0; i++)
1069 	{
1070 		if (us_teclayer_functions[i].value <= LFTYPE) continue;
1071 		if ((func&us_teclayer_functions[i].value) == 0) continue;
1072 		func &= ~us_teclayer_functions[i].value;
1073 		addtoinfstr(infstr, ',');
1074 		addstringtoinfstr(infstr, us_teclayer_functions[i].name);
1075 	}
1076 }
1077 
1078 /*
1079  * Routine to create special text geometry described by "table" in cell "np".
1080  */
us_tecedcreatespecialtext(NODEPROTO * np,SPECIALTEXTDESCR * table)1081 void us_tecedcreatespecialtext(NODEPROTO *np, SPECIALTEXTDESCR *table)
1082 {
1083 	REGISTER NODEINST *ni;
1084 	REGISTER INTBIG i, *pc;
1085 	CHAR line[50], *allocatedname, *str;
1086 	REGISTER VARIABLE *var;
1087 	REGISTER void *infstr;
1088 
1089 	us_tecedfindspecialtext(np, table);
1090 	for(i=0; table[i].funct != 0; i++)
1091 	{
1092 		ni = table[i].ni;
1093 		if (ni == NONODEINST)
1094 		{
1095 			ni = newnodeinst(gen_invispinprim, table[i].x, table[i].x,
1096 				table[i].y, table[i].y, 0, 0, np);
1097 			if (ni == NONODEINST) return;
1098 			allocatedname = 0;
1099 			switch (table[i].funct)
1100 			{
1101 				case TECHLAMBDA:
1102 					(void)esnprintf(line, 50, x_("Lambda: %ld"), (INTBIG)table[i].value);
1103 					str = line;
1104 					break;
1105 				case TECHDESCRIPT:
1106 					infstr = initinfstr();
1107 					formatinfstr(infstr, x_("Description: %s"), (CHAR *)table[i].value);
1108 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1109 					str = allocatedname;
1110 					break;
1111 				case LAYERSTYLE:
1112 					infstr = initinfstr();
1113 					addstringtoinfstr(infstr, TECEDNODETEXTSTYLE);
1114 					if (((INTBIG)table[i].value&NATURE) == SOLIDC) addstringtoinfstr(infstr, x_("solid")); else
1115 					{
1116 						if (((INTBIG)table[i].value&OUTLINEPAT) != 0)
1117 							addstringtoinfstr(infstr, x_("patterned/outlined")); else
1118 								addstringtoinfstr(infstr, x_("patterned"));
1119 					}
1120 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1121 					str = allocatedname;
1122 					break;
1123 				case LAYERCIF:
1124 					infstr = initinfstr();
1125 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTCIF, (CHAR *)table[i].value);
1126 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1127 					str = allocatedname;
1128 					break;
1129 				case LAYERDXF:
1130 					infstr = initinfstr();
1131 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTDXF, (CHAR *)table[i].value);
1132 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1133 					str = allocatedname;
1134 					break;
1135 				case LAYERGDS:
1136 					infstr = initinfstr();
1137 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTGDS, (CHAR *)table[i].value);
1138 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1139 					str = allocatedname;
1140 					break;
1141 				case LAYERFUNCTION:
1142 					infstr = initinfstr();
1143 					addstringtoinfstr(infstr, TECEDNODETEXTFUNCTION);
1144 					us_tecedaddfunstring(infstr, (INTBIG)table[i].value);
1145 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1146 					str = allocatedname;
1147 					break;
1148 				case LAYERLETTERS:
1149 					infstr = initinfstr();
1150 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTLETTERS, (CHAR *)table[i].value);
1151 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1152 					str = allocatedname;
1153 					break;
1154 				case LAYERSPIRES:
1155 					infstr = initinfstr();
1156 					formatinfstr(infstr, x_("%s%g"), TECEDNODETEXTSPICERES, castfloat((INTBIG)table[i].value));
1157 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1158 					str = allocatedname;
1159 					break;
1160 				case LAYERSPICAP:
1161 					infstr = initinfstr();
1162 					formatinfstr(infstr, x_("%s%g"), TECEDNODETEXTSPICECAP, castfloat((INTBIG)table[i].value));
1163 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1164 					str = allocatedname;
1165 					break;
1166 				case LAYERSPIECAP:
1167 					infstr = initinfstr();
1168 					formatinfstr(infstr, x_("%s%g"), TECEDNODETEXTSPICEECAP, castfloat((INTBIG)table[i].value));
1169 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1170 					str = allocatedname;
1171 					break;
1172 				case LAYER3DHEIGHT:
1173 					infstr = initinfstr();
1174 					formatinfstr(infstr, x_("%s%ld"), TECEDNODETEXT3DHEIGHT, (INTBIG)table[i].value);
1175 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1176 					str = allocatedname;
1177 					break;
1178 				case LAYER3DTHICK:
1179 					infstr = initinfstr();
1180 					formatinfstr(infstr, x_("%s%ld"), TECEDNODETEXT3DTHICK, (INTBIG)table[i].value);
1181 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1182 					str = allocatedname;
1183 					break;
1184 				case LAYERPRINTCOL:
1185 					infstr = initinfstr();
1186 					pc = (INTBIG *)table[i].value;
1187 					formatinfstr(infstr, x_("%s%ld,%ld,%ld, %ld,%s"), TECEDNODETEXTPRINTCOL,
1188 						pc[0], pc[1], pc[2], pc[3], (pc[4]==0 ? x_("off") : x_("on")));
1189 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1190 					str = allocatedname;
1191 					break;
1192 				case ARCFUNCTION:
1193 					infstr = initinfstr();
1194 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTFUNCTION,
1195 						us_tecarc_functions[(INTBIG)table[i].value].name);
1196 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1197 					str = allocatedname;
1198 					break;
1199 				case ARCFIXANG:
1200 					if ((INTBIG)table[i].value != 0) str = x_("Fixed-angle: Yes"); else
1201 						str = x_("Fixed-angle: No");
1202 					break;
1203 				case ARCWIPESPINS:
1204 					if ((INTBIG)table[i].value != 0) str = x_("Wipes pins: Yes"); else
1205 						str = x_("Wipes pins: No");
1206 					break;
1207 				case ARCNOEXTEND:
1208 					if ((INTBIG)table[i].value == 0) str = x_("Extend arcs: Yes"); else
1209 						str = x_("Extend arcs: No");
1210 					break;
1211 				case ARCINC:
1212 					(void)esnprintf(line, 50, x_("Angle increment: %ld"), (INTBIG)table[i].value);
1213 					str = line;
1214 					break;
1215 				case NODEFUNCTION:
1216 					infstr = initinfstr();
1217 					formatinfstr(infstr, x_("%s%s"), TECEDNODETEXTFUNCTION,
1218 						nodefunctionname((INTBIG)table[i].value, NONODEINST));
1219 					allocstring(&allocatedname, returninfstr(infstr), el_tempcluster);
1220 					str = allocatedname;
1221 					break;
1222 				case NODESERPENTINE:
1223 					if (table[i].value) str = x_("Serpentine transistor: yes"); else
1224 						str = x_("Serpentine transistor: no");
1225 					break;
1226 				case NODESQUARE:
1227 					if (table[i].value) str = x_("Square node: yes"); else
1228 						str = x_("Square node: no");
1229 					break;
1230 				case NODEWIPES:
1231 					if (table[i].value) str = x_("Invisible with 1 or 2 arcs: yes"); else
1232 						str = x_("Invisible with 1 or 2 arcs: no");
1233 					break;
1234 				case NODELOCKABLE:
1235 					if (table[i].value) str = x_("Lockable: yes"); else
1236 						str = x_("Lockable: no");
1237 					break;
1238 				case NODEMULTICUT:
1239 					esnprintf(line, 100, _("Multicut separation: %s"), frtoa((INTBIG)table[i].value));
1240 					str = line;
1241 					break;
1242 			}
1243 			var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)str, VSTRING|VDISPLAY);
1244 			if (var != NOVARIABLE)
1245 				defaulttextsize(2, var->textdescript);
1246 			(void)setvalkey((INTBIG)ni, VNODEINST, us_edtec_option_key, table[i].funct, VINTEGER);
1247 			endobjectchange((INTBIG)ni, VNODEINST);
1248 			if (allocatedname != 0) efree(allocatedname);
1249 		}
1250 	}
1251 }
1252 
1253 /*
1254  * Routine to locate the nodes with the special node-cell text.  In cell "np", finds
1255  * the relevant text nodes in "table" and loads them into the structure.
1256  */
us_tecedfindspecialtext(NODEPROTO * np,SPECIALTEXTDESCR * table)1257 void us_tecedfindspecialtext(NODEPROTO *np, SPECIALTEXTDESCR *table)
1258 {
1259 	REGISTER NODEINST *ni;
1260 	REGISTER INTBIG i;
1261 	REGISTER VARIABLE *var;
1262 
1263 	/* clear the node assignments */
1264 	for(i=0; table[i].funct != 0; i++)
1265 		table[i].ni = NONODEINST;
1266 
1267 	/* determine the number of special texts here */
1268 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1269 	{
1270 		var = getvalkey((INTBIG)ni, VNODEINST, VINTEGER, us_edtec_option_key);
1271 		if (var == NOVARIABLE) continue;
1272 		for(i=0; table[i].funct != 0; i++)
1273 		{
1274 			if (var->addr != table[i].funct) continue;
1275 			table[i].ni = ni;
1276 			break;
1277 		}
1278 	}
1279 }
1280 
us_tecedplacegeom(POLYGON * poly,NODEPROTO * np)1281 NODEINST *us_tecedplacegeom(POLYGON *poly, NODEPROTO *np)
1282 {
1283 	INTBIG lx, hx, ly, hy, dummy;
1284 	REGISTER NODEINST *nni;
1285 	REGISTER VARIABLE *var;
1286 
1287 	getbbox(poly, &lx, &hx, &ly, &hy);
1288 	switch (poly->style)
1289 	{
1290 		case FILLED:
1291 			if (!isbox(poly, &dummy, &dummy, &dummy, &dummy))
1292 			{
1293 				nni = newnodeinst(art_filledpolygonprim, lx, hx, ly, hy, 0, 0, np);
1294 				if (nni == NONODEINST) return(NONODEINST);
1295 				us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1296 				endobjectchange((INTBIG)nni, VNODEINST);
1297 				return(nni);
1298 			}
1299 			/* FALLTHROUGH */
1300 		case FILLEDRECT:
1301 			nni = newnodeinst(art_filledboxprim, lx, hx, ly, hy, 0, 0, np);
1302 			if (nni == NONODEINST) return(NONODEINST);
1303 			endobjectchange((INTBIG)nni, VNODEINST);
1304 			return(nni);
1305 		case CLOSED:
1306 			if (!isbox(poly, &dummy, &dummy, &dummy, &dummy))
1307 			{
1308 				nni = newnodeinst(art_closedpolygonprim, lx, hx, ly, hy, 0, 0, np);
1309 				if (nni == NONODEINST) return(NONODEINST);
1310 				us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1311 				endobjectchange((INTBIG)nni, VNODEINST);
1312 				return(nni);
1313 			}
1314 			/* FALLTHROUGH */
1315 		case CLOSEDRECT:
1316 			nni = newnodeinst(art_boxprim, lx, hx, ly, hy, 0, 0, np);
1317 			if (nni == NONODEINST) return(NONODEINST);
1318 			endobjectchange((INTBIG)nni, VNODEINST);
1319 			return(nni);
1320 		case CROSSED:
1321 			nni = newnodeinst(art_crossedboxprim, lx, hx, ly, hy, 0,0, np);
1322 			if (nni == NONODEINST) return(NONODEINST);
1323 			endobjectchange((INTBIG)nni, VNODEINST);
1324 			return(nni);
1325 		case OPENED:
1326 			nni = newnodeinst(art_openedpolygonprim, lx, hx, ly, hy, 0, 0, np);
1327 			if (nni == NONODEINST) return(NONODEINST);
1328 			us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1329 			endobjectchange((INTBIG)nni, VNODEINST);
1330 			return(nni);
1331 		case OPENEDT1:
1332 			nni = newnodeinst(art_openeddottedpolygonprim, lx, hx, ly, hy, 0, 0, np);
1333 			if (nni == NONODEINST) return(NONODEINST);
1334 			us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1335 			endobjectchange((INTBIG)nni, VNODEINST);
1336 			return(nni);
1337 		case OPENEDT2:
1338 			nni = newnodeinst(art_openeddashedpolygonprim, lx, hx, ly, hy, 0, 0, np);
1339 			if (nni == NONODEINST) return(NONODEINST);
1340 			us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1341 			endobjectchange((INTBIG)nni, VNODEINST);
1342 			return(nni);
1343 		case OPENEDT3:
1344 			nni = newnodeinst(art_openedthickerpolygonprim, lx, hx, ly, hy, 0, 0, np);
1345 			if (nni == NONODEINST) return(NONODEINST);
1346 			us_tecedsetlist(nni, poly, lx, hx, ly, hy);
1347 			endobjectchange((INTBIG)nni, VNODEINST);
1348 			return(nni);
1349 		case CIRCLE:
1350 			nni = newnodeinst(art_circleprim, lx, hx, ly, hy, 0, 0, np);
1351 			if (nni == NONODEINST) return(NONODEINST);
1352 			endobjectchange((INTBIG)nni, VNODEINST);
1353 			return(nni);
1354 		case THICKCIRCLE:
1355 			nni = newnodeinst(art_thickcircleprim, lx, hx, ly, hy, 0, 0, np);
1356 			if (nni == NONODEINST) return(NONODEINST);
1357 			endobjectchange((INTBIG)nni, VNODEINST);
1358 			return(nni);
1359 		case DISC:
1360 			nni = newnodeinst(art_filledcircleprim, lx, hx, ly, hy, 0, 0, np);
1361 			if (nni == NONODEINST) return(NONODEINST);
1362 			endobjectchange((INTBIG)nni, VNODEINST);
1363 			return(nni);
1364 		case CIRCLEARC:
1365 			nni = newnodeinst(art_circleprim, lx, hx, ly, hy, 0, 0, np);
1366 			if (nni == NONODEINST) return(NONODEINST);
1367 			setarcdegrees(nni, 0.0, 45.0*EPI/180.0);
1368 			endobjectchange((INTBIG)nni, VNODEINST);
1369 			return(nni);
1370 		case THICKCIRCLEARC:
1371 			nni = newnodeinst(art_thickcircleprim, lx, hx, ly, hy, 0, 0, np);
1372 			if (nni == NONODEINST) return(NONODEINST);
1373 			setarcdegrees(nni, 0.0, 45.0*EPI/180.0);
1374 			endobjectchange((INTBIG)nni, VNODEINST);
1375 			return(nni);
1376 		case TEXTCENT:
1377 			nni = newnodeinst(gen_invispinprim, lx, hx, ly, hy, 0, 0, np);
1378 			if (nni == NONODEINST) return(NONODEINST);
1379 			var = setvalkey((INTBIG)nni, VNODEINST, art_messagekey,
1380 				(INTBIG)poly->string, VSTRING|VDISPLAY);
1381 			if (var != NOVARIABLE) TDSETPOS(var->textdescript, VTPOSCENT);
1382 			endobjectchange((INTBIG)nni, VNODEINST);
1383 			return(nni);
1384 		case TEXTBOTLEFT:
1385 			nni = newnodeinst(gen_invispinprim, lx, hx, ly, hy, 0, 0, np);
1386 			if (nni == NONODEINST) return(NONODEINST);
1387 			var = setvalkey((INTBIG)nni, VNODEINST, art_messagekey,
1388 				(INTBIG)poly->string, VSTRING|VDISPLAY);
1389 			if (var != NOVARIABLE) TDSETPOS(var->textdescript, VTPOSUPRIGHT);
1390 			endobjectchange((INTBIG)nni, VNODEINST);
1391 			return(nni);
1392 		case TEXTBOTRIGHT:
1393 			nni = newnodeinst(gen_invispinprim, lx, hx, ly, hy, 0, 0, np);
1394 			if (nni == NONODEINST) return(NONODEINST);
1395 			var = setvalkey((INTBIG)nni, VNODEINST, art_messagekey,
1396 				(INTBIG)poly->string, VSTRING|VDISPLAY);
1397 			if (var != NOVARIABLE) TDSETPOS(var->textdescript, VTPOSUPLEFT);
1398 			endobjectchange((INTBIG)nni, VNODEINST);
1399 			return(nni);
1400 		case TEXTBOX:
1401 			nni = newnodeinst(gen_invispinprim, lx, hx, ly, hy, 0, 0, np);
1402 			if (nni == NONODEINST) return(NONODEINST);
1403 			var = setvalkey((INTBIG)nni, VNODEINST, art_messagekey,
1404 				(INTBIG)poly->string, VSTRING|VDISPLAY);
1405 			if (var != NOVARIABLE) TDSETPOS(var->textdescript, VTPOSBOXED);
1406 			endobjectchange((INTBIG)nni, VNODEINST);
1407 			return(nni);
1408 	}
1409 	return(NONODEINST);
1410 }
1411 
us_tecedsetlist(NODEINST * ni,POLYGON * poly,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy)1412 void us_tecedsetlist(NODEINST *ni, POLYGON *poly, INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy)
1413 {
1414 	REGISTER INTBIG *list;
1415 	REGISTER INTBIG i;
1416 
1417 	list = emalloc((poly->count*2*SIZEOFINTBIG), el_tempcluster);
1418 	if (list == 0) return;
1419 	for(i=0; i<poly->count; i++)
1420 	{
1421 		list[i*2] = poly->xv[i] - (hx+lx)/2;
1422 		list[i*2+1] = poly->yv[i] - (hy+ly)/2;
1423 	}
1424 	(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)list,
1425 		VINTEGER|VISARRAY|((poly->count*2)<<VLENGTHSH));
1426 	efree((CHAR *)list);
1427 }
1428