1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrcomcd.c
6  * User interface tool: command handler for C through D
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 "edialogs.h"
35 #include "usr.h"
36 #include "usrtrack.h"
37 #include "database.h"
38 #include "tecgen.h"
39 #include "tecart.h"
40 #include "tecschem.h"
41 #include "efunction.h"
42 #include "usrdiacom.h"
43 #include <math.h>
44 
45 #define MAXLINE	   200		/* max characters on color map input line */
46 static struct {
47 	INTBIG bits;
48 	INTBIG set;
49 } us_overlappables[] =
50 {
51 	{LAYERT1, 0},
52 	{LAYERT2, 0},
53 	{LAYERT3, 0},
54 	{LAYERT4, 0},
55 	{LAYERT5, 0},
56 	{0, 0}
57 };
58 
us_color(INTBIG count,CHAR * par[])59 void us_color(INTBIG count, CHAR *par[])
60 {
61 	REGISTER INTBIG i, j, k, l, high, totalcolor, max, red, green, blue,
62 		newmax, style, newraster;
63 	CHAR line[MAXLINE], *layerlabel[5], *layerabbrev[5], *filename, *truename, **layernames;
64 	INTBIG redt[256], greent[256], bluet[256], rr, rg, rb, *layerdata;
65 	float hue, sat, inten, amt;
66 	REGISTER VARIABLE *varred, *vargreen, *varblue;
67 	REGISTER CHAR *pp, *orig, *s, *la;
68 	GRAPHICS *desc;
69 	REGISTER FILE *f;
70 	extern COMCOMP us_colorp, us_colorentryp, us_colorreadp, us_colorwritep;
71 	REGISTER void *infstr;
72 
73 	if (count == 0)
74 	{
75 		count = ttygetparam(M_("COLOR option: "), &us_colorp, MAXPARS, par);
76 		if (count == 0)
77 		{
78 			us_abortedmsg();
79 			return;
80 		}
81 	}
82 	l = estrlen(pp = par[0]);
83 
84 	if (namesamen(pp, x_("black-background"), l) == 0 && l >= 1)
85 	{
86 		us_getcolormap(el_curtech, COLORSBLACK, TRUE);
87 		ttyputverbose(M_("Black-background colormap loaded"));
88 		return;
89 	}
90 
91 	if (namesamen(pp, x_("white-background"), l) == 0 && l >= 1)
92 	{
93 		us_getcolormap(el_curtech, COLORSWHITE, TRUE);
94 		ttyputverbose(M_("White-background colormap loaded"));
95 		return;
96 	}
97 
98 	if (namesamen(pp, x_("default"), l) == 0 && l >= 1)
99 	{
100 		us_getcolormap(el_curtech, COLORSDEFAULT, TRUE);
101 		ttyputverbose(M_("Default colormap loaded"));
102 		return;
103 	}
104 
105 	if (namesamen(pp, x_("highlight"), l) == 0 && l >= 1)
106 	{
107 		if (us_needwindow()) return;
108 		if (count < 2)
109 		{
110 			ttyputusage(x_("color highlight LAYERLETTERS [AMOUNT]"));
111 			return;
112 		}
113 		amt = 0.2f;
114 		if (count >= 3)
115 		{
116 			amt = (float)atofr(par[2]);
117 			amt /= WHOLE;
118 		}
119 		if (amt < 0.0 || amt > 1.0)
120 		{
121 			us_abortcommand(_("Highlight amount must be from 0 to 1"));
122 			return;
123 		}
124 
125 		/* check the list of letters */
126 		for(k=0; us_overlappables[k].bits != 0; k++)
127 			us_overlappables[k].set = 0;
128 		for(i=0; par[1][i] != 0 && par[1][i] != '('; i++)
129 		{
130 			for(j=0; j<el_curtech->layercount; j++)
131 			{
132 				la = us_layerletters(el_curtech, j);
133 				for(k=0; la[k] != 0; k++) if (par[1][i] == la[k]) break;
134 				if (la[k] != 0) break;
135 			}
136 			if (j >= el_curtech->layercount)
137 			{
138 				us_abortcommand(_("Unknown layer letter: %c"), par[1][i]);
139 				return;
140 			}
141 			for(k=0; us_overlappables[k].bits != 0; k++)
142 				if (el_curtech->layers[j]->bits == us_overlappables[k].bits) break;
143 			if (us_overlappables[k].bits == 0)
144 			{
145 				us_abortcommand(_("Layer %s(%c) is not transparent"), layername(el_curtech, j), par[1][i]);
146 				return;
147 			}
148 			us_overlappables[k].set = 1;
149 		}
150 
151 		/* get the color map */
152 		varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
153 		vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
154 		varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
155 		if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
156 		{
157 			ttyputerr(_("Cannot get current color map"));
158 			return;
159 		}
160 
161 		/* copy the color arrays from the variables */
162 		for(i=0; i<256; i++)
163 		{
164 			redt[i] = ((INTBIG *)varred->addr)[i];
165 			greent[i] = ((INTBIG *)vargreen->addr)[i];
166 			bluet[i] = ((INTBIG *)varblue->addr)[i];
167 		}
168 
169 		/* adjust the color arrays */
170 		for(i=1; i<256; i++)
171 		{
172 			/* ignore if nonoverlappable, grid, or highlight */
173 			if ((i&(LAYERG|LAYERH|LAYEROE)) != 0) continue;
174 
175 			/* skip if it is one of the highlighted layers */
176 			for(k=0; us_overlappables[k].bits != 0; k++)
177 				if ((us_overlappables[k].bits&i) != 0 && us_overlappables[k].set != 0) break;
178 			if (us_overlappables[k].bits != 0) continue;
179 
180 			/* dim the layer */
181 			us_rgbtohsv(redt[i], greent[i], bluet[i], &hue, &sat, &inten);
182 			sat *= amt;
183 			us_hsvtorgb(hue, sat, inten, &rr, &rg, &rb);
184 			redt[i] = rr;   greent[i] = rg;   bluet[i] = rb;
185 		}
186 
187 		/* set the new color map */
188 		startobjectchange((INTBIG)us_tool, VTOOL);
189 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)redt,
190 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
191 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)greent,
192 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
193 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)bluet,
194 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
195 		endobjectchange((INTBIG)us_tool, VTOOL);
196 		return;
197 	}
198 
199 	if ((namesamen(pp, x_("entry"), l) == 0 ||
200 		namesamen(pp, x_("pattern"), l) == 0) && l >= 1)
201 	{
202 		/* force pattern references on black&white display */
203 		style = *pp;
204 		if (us_needwindow()) return;
205 
206 		/* get the entry number */
207 		if (count < 2)
208 		{
209 			count = ttygetparam(M_("Entry: "), &us_colorentryp, MAXPARS-1, &par[1]) + 1;
210 			if (count == 1)
211 			{
212 				us_abortedmsg();
213 				return;
214 			}
215 		}
216 
217 		if (style == 'p')
218 		{
219 			/* pattern specification */
220 			j = el_curtech->layercount;
221 			totalcolor = us_getcolormapentry(par[1], TRUE);
222 		} else
223 		{
224 			/* color map entry specification */
225 			j = el_maplength;
226 			totalcolor = us_getcolormapentry(par[1], FALSE);
227 		}
228 		if (totalcolor < 0) return;
229 		if (totalcolor >= j)
230 		{
231 			us_abortcommand(_("Entry must be from 0 to %ld"), j-1);
232 			return;
233 		}
234 
235 		/* get color arrays */
236 		varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
237 		vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
238 		varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
239 		if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
240 		{
241 			ttyputerr(_("Cannot get current color map"));
242 			return;
243 		}
244 
245 		/* if more values specified, get new entry */
246 		if (count >= 3)
247 		{
248 			if (style == 'p')
249 			{
250 				/* get a stipple pattern for this layer */
251 				desc = el_curtech->layers[totalcolor];
252 				pp = par[2];
253 				for(j=0; j<8; j++)
254 				{
255 					if (*pp == 0) pp = par[2];
256 					if (*pp == '/')
257 					{
258 						pp++;
259 						continue;
260 					}
261 					newraster = myatoi(pp);
262 					(void)setind((INTBIG)desc, VGRAPHICS, x_("raster"), j, newraster);
263 					while (*pp != '/' && *pp != 0) pp++;
264 					if (*pp == '/') pp++;
265 				}
266 			} else
267 			{
268 				/* get three colors for the map */
269 				if (count < 5)
270 				{
271 					ttyputusage(x_("color entry INDEX [RED GREEN BLUE]"));
272 					return;
273 				}
274 				us_setcolorentry(totalcolor, myatoi(par[2]), myatoi(par[3]),
275 					myatoi(par[4]), 0, TRUE);
276 			}
277 		}
278 
279 		/* report the current color values */
280 		if (style == 'p')
281 		{
282 			ttyputmsg(_("Entry %ld (%s) is bits:"), totalcolor,
283 				layername(el_curtech, totalcolor));
284 			desc = el_curtech->layers[totalcolor];
285 			for(j=0; j<8; j++)
286 			{
287 				(void)esnprintf(line, MAXLINE, x_("0x%04x |"), desc->raster[j]&0xFFFF);
288 				for(k=0; k<16; k++)
289 					if ((desc->raster[j] & (1<<(15-k))) != 0)
290 						(void)estrcat(line, x_("X")); else
291 							(void)estrcat(line, x_(" "));
292 				(void)estrcat(line, x_("|"));
293 				ttyputmsg(x_("%s"), line);
294 			}
295 		} else us_printcolorvalue(totalcolor);
296 		return;
297 	}
298 
299 	if (namesamen(pp, x_("mix"), l) == 0 && l >= 1)
300 	{
301 		if (us_needwindow()) return;
302 		for(i=0; i<5; i++) layerlabel[i] = 0;
303 		j = el_curtech->layercount;
304 		for(i=0; i<j; i++)
305 		{
306 			desc = el_curtech->layers[i];
307 			switch (desc->bits)
308 			{
309 				case LAYERT1: k = 0;   break;
310 				case LAYERT2: k = 1;   break;
311 				case LAYERT3: k = 2;   break;
312 				case LAYERT4: k = 3;   break;
313 				case LAYERT5: k = 4;   break;
314 				default:      k = -1;  break;
315 			}
316 			if (k < 0) continue;
317 			if (layerlabel[k] != 0) continue;
318 			layerlabel[k] = layername(el_curtech, i);
319 			layerabbrev[k] = (CHAR *)emalloc(2 * SIZEOFCHAR, el_tempcluster);
320 			layerabbrev[k][0] = *us_layerletters(el_curtech, i);
321 			layerabbrev[k][1] = 0;
322 		}
323 		layerdata = us_getprintcolors(el_curtech);
324 		if (layerdata == 0)
325 		{
326 			ttyputerr(_("Cannot get print colors for technology '%s'"), el_curtech->techname);
327 			return;
328 		}
329 		for(i=0; i<5; i++) if (layerlabel[i] == 0)
330 		{
331 			layerlabel[i] = x_("UNUSED");
332 			(void)allocstring(&layerabbrev[i], x_("?"), el_tempcluster);
333 		}
334 		layernames = (CHAR **)emalloc(el_curtech->layercount*(sizeof (CHAR *)), el_tempcluster);
335 		if (layernames == 0) return;
336 		for(i=0; i<el_curtech->layercount; i++)
337 			layernames[i] = layername(el_curtech, i);
338 		if (us_colormixdlog(layerlabel, el_curtech->layercount, layernames, layerdata))
339 		{
340 			/* data changed: update the print colors (other information is already set) */
341 			setval((INTBIG)el_curtech, VTECHNOLOGY, x_("USER_print_colors"), (INTBIG)layerdata,
342 				VINTEGER|VISARRAY|((el_curtech->layercount*5)<<VLENGTHSH));
343 		}
344 		for(i=0; i<5; i++) efree(layerabbrev[i]);
345 		efree((CHAR *)layernames);
346 		return;
347 	}
348 
349 	if (namesamen(pp, x_("read"), l) == 0 && l >= 1)
350 	{
351 		if (count < 2)
352 		{
353 			infstr = initinfstr();
354 			addstringtoinfstr(infstr, x_("color/"));
355 			addstringtoinfstr(infstr, _("Color Map File"));
356 			count = ttygetparam(returninfstr(infstr), &us_colorreadp, MAXPARS-1, &par[1]) + 1;
357 			if (count == 1)
358 			{
359 				us_abortedmsg();
360 				return;
361 			}
362 		}
363 		orig = par[1];
364 
365 		/* get color map from file */
366 		f = xopen(orig, us_filetypecolormap, el_libdir, &filename);
367 		if (f == NULL)
368 		{
369 			us_abortcommand(_("Cannot find %s"), orig);
370 			return;
371 		}
372 		ttyputmsg(_("Reading %s"), orig);
373 
374 		/* see if technology name is right */
375 		(void)xfgets(line, MAXLINE, f);
376 		if (estrncmp(line, x_("technology="), 11) != 0)
377 		{
378 			us_abortcommand(_("Invalid color map file"));
379 			xclose(f);
380 			return;
381 		}
382 		pp = &line[11];
383 		if (estrcmp(pp, el_curtech->techname) != 0)
384 			ttyputverbose(M_("Warning: color map is for %s technology"), pp);
385 
386 		max = 0;
387 		for(;;)
388 		{
389 			if (xfgets(line, MAXLINE, f))
390 			{
391 				us_abortcommand(_("Map ends prematurely"));
392 				return;
393 			}
394 			(void)estrcat(line, x_("\t\t\t\t"));
395 			pp = line;   red = eatoi(pp);
396 			while (*pp != '\t' && *pp != 0) pp++;  green = eatoi(++pp);
397 			while (*pp != '\t' && *pp != 0) pp++;  blue = eatoi(++pp);
398 			while (*pp != '\t' && *pp != 0) pp++;  newmax = eatoi(++pp);
399 			if (newmax < max || newmax >= 256)
400 			{
401 				us_abortcommand(_("Bad map indices: %s"), line);
402 				xclose(f);
403 				return;
404 			}
405 			for(; max <= newmax; max++)
406 			{
407 				redt[max] = red&0377;
408 				greent[max] = green&0377;
409 				bluet[max] = blue&0377;
410 			}
411 			if (max >= 256) break;
412 		}
413 
414 		/* set the color map */
415 		startobjectchange((INTBIG)us_tool, VTOOL);
416 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)redt,
417 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
418 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)greent,
419 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
420 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)bluet,
421 			VINTEGER|VISARRAY|(256<<VLENGTHSH));
422 		endobjectchange((INTBIG)us_tool, VTOOL);
423 
424 		/* now get the bit-map information */
425 		if (xfgets(line, MAXLINE, f))
426 		{
427 			ttyputmsg(_("Warning: no bit-map information in file"));
428 			return;
429 		}
430 		j = eatoi(line);
431 		high = el_curtech->layercount;
432 		for(i=0; i<j; i++)
433 		{
434 			if (xfgets(line, MAXLINE, f))
435 			{
436 				ttyputmsg(_("Warning: EOF during bit-map data"));
437 				break;
438 			}
439 			for(k=0; k<high; k++)
440 			{
441 				pp = us_layerletters(el_curtech, k);
442 				for(l=0; pp[l] != 0; l++) if (pp[l] == line[0]) break;
443 				if (pp[l] != 0)
444 				{
445 					desc = el_curtech->layers[k];
446 					pp = &line[1];
447 					for(l=0; l<8; l++)
448 					{
449 						while (*pp != ' ' && *pp != 0) pp++;
450 						newraster = myatoi(++pp);
451 						(void)setind((INTBIG)desc, VGRAPHICS, x_("raster"), l, newraster);
452 					}
453 					break;
454 				}
455 			}
456 			if (k >= high) ttyputmsg(_("Warning: no layer '%c' in this technology"), line[0]);
457 		}
458 		xclose(f);
459 
460 		ttyputmsg(_("Color map in %s read"), orig);
461 		return;
462 	}
463 
464 	if (namesamen(pp, x_("write"), l) == 0 && l >= 1)
465 	{
466 		if (count < 2)
467 		{
468 			infstr = initinfstr();
469 			addstringtoinfstr(infstr, x_("color/"));
470 			addstringtoinfstr(infstr, _("Color map file name: "));
471 			count = ttygetparam(returninfstr(infstr), &us_colorwritep, MAXPARS-1, &par[1]) + 1;
472 			if (count == 1)
473 			{
474 				us_abortedmsg();
475 				return;
476 			}
477 		}
478 		orig = par[1];
479 
480 		/* get color arrays */
481 		varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
482 		vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
483 		varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
484 		if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
485 		{
486 			ttyputerr(_("Cannot get current color map"));
487 			return;
488 		}
489 
490 		/* write color map to file */
491 		f = xcreate(orig, us_filetypecolormap, _("Color Map File"), &truename);
492 		if (f == NULL)
493 		{
494 			if (truename != 0) us_abortcommand(_("Cannot write %s"), truename);
495 			return;
496 		}
497 		xprintf(f, x_("technology=%s\n"), el_curtech->techname);
498 		for(i=0; i<256; i++)
499 			if (i == 255 || ((INTBIG *)varred->addr)[i] != ((INTBIG *)varred->addr)[i+1] ||
500 				((INTBIG *)vargreen->addr)[i] != ((INTBIG *)vargreen->addr)[i+1] ||
501 					((INTBIG *)varblue->addr)[i] != ((INTBIG *)varblue->addr)[i+1])
502 		{
503 			xprintf(f, x_("%ld\t%ld\t%ld\t%ld\n"), ((INTBIG *)varred->addr)[i],
504 				((INTBIG *)vargreen->addr)[i], ((INTBIG *)varblue->addr)[i], i);
505 		}
506 
507 		/* write the bit maps */
508 		high = el_curtech->layercount;
509 		xprintf(f, x_("%ld\n"), high);
510 		for(i=0; i<high; i++)
511 		{
512 			desc = el_curtech->layers[i];
513 			s = us_layerletters(el_curtech, i);
514 			xprintf(f, x_("%c"), s[0]);
515 			for(j=0; j<8; j++)
516 				xprintf(f, x_(" 0%o"), desc->raster[j] & 0xFFFF);
517 			xprintf(f, x_("\n"));
518 		}
519 		xclose(f);
520 		ttyputverbose(M_("%s written"), truepath(orig));
521 		return;
522 	}
523 
524 	ttyputbadusage(x_("color"));
525 }
526 
us_commandfile(INTBIG count,CHAR * par[])527 void us_commandfile(INTBIG count, CHAR *par[])
528 {
529 	REGISTER FILE *in;
530 	REGISTER BOOLEAN verbose;
531 	REGISTER CHAR *pp;
532 	CHAR *filename;
533 	REGISTER MACROPACK *lastmacropack;
534 	extern COMCOMP us_colorreadp;
535 	REGISTER void *infstr;
536 
537 	if (count >= 2 && namesamen(par[1], x_("verbose"), estrlen(par[1])) == 0) verbose = TRUE; else
538 		verbose = FALSE;
539 
540 	if (count == 0)
541 	{
542 		infstr = initinfstr();
543 		addstringtoinfstr(infstr, x_("macro/"));
544 		addstringtoinfstr(infstr, _("Command File: "));
545 		count = ttygetparam(returninfstr(infstr), &us_colorreadp, MAXPARS, par);
546 		if (count == 0)
547 		{
548 			us_abortedmsg();
549 			return;
550 		}
551 	}
552 	pp = par[0];
553 
554 	in = xopen(pp, us_filetypemacro, el_libdir, &filename);
555 	if (in == NULL)
556 	{
557 		us_abortcommand(_("Command file %s not found"), pp);
558 		return;
559 	}
560 
561 	/* create a new macro package entry */
562 	lastmacropack = us_curmacropack;
563 	us_curmacropack = us_newmacropack(pp);
564 
565 	/* read the commands */
566 	us_docommands(in, verbose, x_(""));
567 	xclose(in);
568 
569 	/* now there is no macro package */
570 	us_curmacropack = lastmacropack;
571 }
572 
us_constraint(INTBIG count,CHAR * par[])573 void us_constraint(INTBIG count, CHAR *par[])
574 {
575 	REGISTER INTBIG l, c;
576 	REGISTER CHAR *pp;
577 
578 	/* get the name of the constraint solver */
579 	if (count <= 1)
580 	{
581 		ttyputusage(x_("constraint (use | tell) SOLVER [OPTIONS]"));
582 		return;
583 	}
584 	for(c=0; el_constraints[c].conname != 0; c++)
585 		if (namesame(el_constraints[c].conname, par[1]) == 0) break;
586 	if (el_constraints[c].conname == 0)
587 	{
588 		us_abortcommand(_("No constraint solver called %s"), par[1]);
589 		return;
590 	}
591 
592 	l = estrlen(pp = par[0]);
593 
594 	if (namesamen(pp, x_("tell"), l) == 0 && l >= 1)
595 	{
596 		(*(el_constraints[c].setmode))(count-2, &par[2]);
597 		return;
598 	}
599 
600 	if (namesamen(pp, x_("use"), l) == 0 && l >= 1)
601 	{
602 		if (el_curconstraint == &el_constraints[c])
603 		{
604 			ttyputerr(_("Already using that constraint solver"));
605 			return;
606 		}
607 		us_clearhighlightcount();
608 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_constraint_key,
609 			(INTBIG)&el_constraints[c], VCONSTRAINT|VDONTSAVE);
610 		ttyputmsg(M_("Switching to %s"), TRANSLATE(el_constraints[c].condesc));
611 		return;
612 	}
613 
614 	ttyputbadusage(x_("constraint"));
615 }
616 
us_copycell(INTBIG count,CHAR * par[])617 void us_copycell(INTBIG count, CHAR *par[])
618 {
619 	REGISTER NODEPROTO *np, *onp, *oinp;
620 	REGISTER LIBRARY *fromlib, *tolib;
621 	REGISTER CHAR *pt, *ppt, *lastch, save;
622 	extern COMCOMP us_copycellp;
623 	REGISTER NODEINST *ni, *newni;
624 	REGISTER VIEW *nview;
625 	REGISTER INTBIG i;
626 	CHAR *subpar[5];
627 	BOOLEAN quiet, norelatedviews, showcopy, move, nosubcells, newframe, useexisting;
628 	INTBIG lx, hx, ly, hy;
629 	REGISTER void *infstr;
630 	extern COMCOMP us_yesnop;
631 
632 	/* get name of old cell */
633 	if (count == 0)
634 	{
635 		count = ttygetparam(M_("Old cell name: "), &us_copycellp, MAXPARS, par);
636 		if (count == 0)
637 		{
638 			us_abortedmsg();
639 			return;
640 		}
641 	}
642 	np = getnodeproto(par[0]);
643 	if (np == NONODEPROTO)
644 	{
645 		us_abortcommand(_("Cannot find source cell %s"), par[0]);
646 		return;
647 	}
648 	if (np->primindex != 0)
649 	{
650 		us_abortcommand(_("Cannot copy primitives"));
651 		return;
652 	}
653 	fromlib = np->lib;
654 	tolib = fromlib;
655 
656 	/* get name of new cell */
657 	newframe = showcopy = quiet = norelatedviews = move = nosubcells = useexisting = FALSE;
658 	if (count <= 1) pt = np->protoname; else
659 	{
660 		/* if there is a version number in the new name, remove it */
661 		for(ppt = par[1]; *ppt != 0; ppt++) if (*ppt == ';') break;
662 		if (*ppt != 0)
663 		{
664 			infstr = initinfstr();
665 			*ppt = 0;
666 			addstringtoinfstr(infstr, par[1]);
667 			*ppt++ = ';';
668 			for( ; *ppt != 0; ppt++) if (*ppt == '{') break;
669 			addstringtoinfstr(infstr, ppt);
670 			par[1] = returninfstr(infstr);
671 		}
672 		pt = par[1];
673 
674 		for(ppt = pt; *ppt != 0; ppt++) if (*ppt == ':') break;
675 		if (*ppt == ':')
676 		{
677 			*ppt++ = 0;
678 			tolib = getlibrary(pt);
679 			if (tolib == NOLIBRARY)
680 			{
681 				us_abortcommand(_("Unknown destination library: %s"), pt);
682 				return;
683 			}
684 			pt = ppt;
685 		}
686 		if (namesame(pt, x_("{ic}")) == 0 || namesame(pt, x_("{sk}")) == 0)
687 		{
688 			infstr = initinfstr();
689 			addstringtoinfstr(infstr, np->protoname);
690 			addstringtoinfstr(infstr, par[1]);
691 			pt = returninfstr(infstr);
692 		}
693 		while (count > 2)
694 		{
695 			i = estrlen(ppt = par[2]);
696 			if (namesamen(ppt, x_("quiet"), i) == 0) quiet = TRUE; else
697 			if (namesamen(ppt, x_("move"), i) == 0) move = TRUE; else
698 			if (namesamen(ppt, x_("replace-copy"), i) == 0) showcopy = TRUE; else
699 			if (namesamen(ppt, x_("show-copy"), i) == 0) showcopy = newframe = TRUE; else
700 			if (namesamen(ppt, x_("no-related-views"), i) == 0 && i >= 4) norelatedviews = TRUE; else
701 			if (namesamen(ppt, x_("no-subcells"), i) == 0 && i >= 4) nosubcells = TRUE; else
702 			if (namesamen(ppt, x_("use-existing-subcells"), i) == 0) useexisting = TRUE; else
703 			{
704 				ttyputbadusage(x_("copycell"));
705 				return;
706 			}
707 			count--;
708 			par++;
709 		}
710 	}
711 
712 	/* see if icon generation is requested */
713 	i = estrlen(pt);
714 	if (count > 1 && i > 4 && namesame(&pt[i-4], x_("{ic}")) == 0 && np->cellview != el_iconview)
715 	{
716 		/* cannot iconize text-only views */
717 		if ((np->cellview->viewstate&TEXTVIEW) != 0)
718 		{
719 			us_abortcommand(_("Cannot iconize textual views: only layout and schematic"));
720 			return;
721 		}
722 
723 		/* cannot cross libraries when iconizing */
724 		if (fromlib != tolib)
725 		{
726 			us_abortcommand(_("Can only generate icons within the same library"));
727 			return;
728 		}
729 
730 		/* generate the icon */
731 		onp = us_makeiconcell(np->firstportproto, np->protoname, pt, tolib);
732 		if (onp == NONODEPROTO) return;
733 		if (!quiet)
734 			ttyputmsg(_("Cell %s created with an iconic representation of %s"),
735 				describenodeproto(onp), describenodeproto(np));
736 		if (showcopy)
737 		{
738 			us_fullview(onp, &lx, &hx, &ly, &hy);
739 			if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
740 			us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
741 		}
742 		return;
743 	}
744 
745 	/* see if skeletonization is requested */
746 	i = estrlen(pt);
747 	if (count > 1 && i > 4 && namesame(&pt[i-4], x_("{sk}")) == 0 && np->cellview != el_skeletonview)
748 	{
749 		onp = us_skeletonize(np, pt, tolib, quiet);
750 		if (onp == NONODEPROTO) return;
751 		if (showcopy)
752 		{
753 			us_fullview(onp, &lx, &hx, &ly, &hy);
754 			if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
755 			us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
756 		}
757 		return;
758 	}
759 
760 	/* see if the name already exists in the destination library */
761 	for(onp = tolib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
762 	{
763 		if (namesame(onp->protoname, pt) != 0) continue;
764 		if (np->cellview == onp->cellview) break;
765 	}
766 	if (onp != NONODEPROTO)
767 	{
768 		infstr = initinfstr();
769 		formatinfstr(infstr, _("Cell %s already exists; create a new version?"), describenodeproto(onp));
770 		i = ttygetparam(returninfstr(infstr), &us_yesnop, MAXPARS, subpar);
771 		if (i > 0 && namesamen(subpar[0], x_("no"), estrlen(subpar[0])) == 0) return;
772 	}
773 
774 	/* if going within the same library, let the database do it */
775 	if (fromlib == tolib)
776 	{
777 		onp = copynodeproto(np, tolib, pt, FALSE);
778 		if (onp == NONODEPROTO)
779 		{
780 			ttyputerr(_("Error copying cell"));
781 			return;
782 		}
783 		if (onp->cellview != np->cellview || !insamecellgrp(onp, np))
784 		{
785 			if (!quiet)
786 				ttyputmsg(_("Cell %s copied to %s"), describenodeproto(np),
787 					describenodeproto(onp));
788 
789 			/* see if renaming a schematic with an icon of itself inside */
790 			for(ppt = pt; *ppt != 0; ppt++) if (*ppt == '{') break;
791 			if (*ppt == 0)
792 			{
793 				/* just a rename, not to a different view type */
794 				for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
795 				{
796 					if (ni->proto->primindex != 0) continue;
797 					if (isiconof(ni->proto, np)) break;
798 				}
799 				if (ni != NONODEINST)
800 				{
801 					/* need a properly-named icon: see if it exists */
802 					infstr = initinfstr();
803 					formatinfstr(infstr, x_("%s:%s{ic}"), tolib->libname, pt);
804 					oinp = getnodeproto(returninfstr(infstr));
805 					if (oinp == NONODEPROTO)
806 					{
807 						/* duplicate the icon and replace the old one with the duplicate */
808 						oinp = copynodeproto(ni->proto, tolib, pt, FALSE);
809 					}
810 					if (oinp == NONODEPROTO)
811 					{
812 						ttyputerr(_("Error duplicating icon node %s to %s"),
813 							describenodeinst(ni), pt);
814 					} else
815 					{
816 						startobjectchange((INTBIG)ni, VNODEINST);
817 						newni = replacenodeinst(ni, oinp, TRUE, TRUE);
818 						if (newni != NONODEINST)
819 							endobjectchange((INTBIG)newni, VNODEINST);
820 					}
821 				}
822 			}
823 		} else
824 		{
825 			if (!quiet)
826 				ttyputmsg(_("New version of cell %s created, old is %s"),
827 					describenodeproto(onp), describenodeproto(np));
828 
829 			/* set current nodeproto to itself to redisplay its name */
830 			if (np == getcurcell())
831 				(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
832 
833 			/* update display of any unexpanded old versions */
834 			for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
835 			{
836 				if ((ni->userbits&NEXPAND) != 0) continue;
837 				startobjectchange((INTBIG)ni, VNODEINST);
838 				endobjectchange((INTBIG)ni, VNODEINST);
839 			}
840 		}
841 		if (showcopy)
842 		{
843 			us_fullview(onp, &lx, &hx, &ly, &hy);
844 			if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
845 			us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
846 		}
847 		return;
848 	}
849 
850 	/* get the new view type */
851 	nview = np->cellview;
852 	for(ppt = pt; *ppt != 0; ppt++) if (*ppt == '{') break;
853 	if (*ppt == '{')
854 	{
855 		lastch = &pt[estrlen(pt)-1];
856 		if (*lastch != '}')
857 		{
858 			us_abortcommand(_("View name '%s'must end with a '}'"), &ppt[1]);
859 			return;
860 		}
861 		*lastch = 0;
862 		nview = getview(&ppt[1]);
863 		*lastch = '}';
864 		if (nview == NOVIEW)
865 		{
866 			us_abortcommand(_("Unknown view abbreviation: %s"), ppt);
867 			return;
868 		}
869 	}
870 
871 	save = *ppt;
872 	*ppt = 0;
873 	onp = us_copyrecursively(np, pt, tolib, nview, TRUE, move, x_(""),
874 		norelatedviews, nosubcells, useexisting);
875 	*ppt = save;
876 	if (showcopy)
877 	{
878 		us_fullview(onp, &lx, &hx, &ly, &hy);
879 		if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
880 		us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
881 	}
882 }
883 
us_create(INTBIG count,CHAR * par[])884 void us_create(INTBIG count, CHAR *par[])
885 {
886 	REGISTER NODEPROTO *np, *curcell;
887 	REGISTER NODEINST *ni, *newno, *ni2;
888 	REGISTER PORTPROTO *pp, *ppt, *fpt, *pp1, *pp2;
889 	PORTPROTO *fromport, *toport;
890 	REGISTER ARCPROTO *ap, *wantap;
891 	REGISTER ARCINST *ai, *newai;
892 	REGISTER TECHNOLOGY *tech;
893 	NODEINST *ani[2];
894 	REGISTER INTBIG ang, pangle, l, bestdist, bestdist1, bestdist2, wid, truewid, i, j, k,
895 		bits1, bits2, dist, alignment, edgealignment;
896 	BOOLEAN remainhighlighted, ishor, isver, join, angledcreate,
897 		waitfordown, centeredprimitives, getcontents;
898 	INTBIG px, py, nx, ny, cx, cy, x, y, xp[2], yp[2], xcur, ycur, otheralign, pxs, pys,
899 		lx, hx, ly, hy;
900 	PORTPROTO *app[2], *splitpp;
901 	REGISTER VARIABLE *var;
902 	static POLYGON *poly = NOPOLYGON, *poly2 = NOPOLYGON;
903 	ARCINST *alt1, *alt2;
904 	NODEINST *con1, *con2;
905 	CHAR *oldarcname, *newpar[2];
906 	HIGHLIGHT newhigh, *high;
907 	REGISTER GEOM *foundgeom, *geom, **list;
908 	GEOM *fromgeom, *togeom;
909 	extern GRAPHICS us_hbox;
910 
911 	/* get polygon */
912 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
913 	(void)needstaticpolygon(&poly2, 4, us_tool->cluster);
914 
915 	/* make sure there is a cell being edited */
916 	if (us_needwindow()) return;
917 	if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
918 	{
919 		us_abortcommand(_("Can only place components in graphical editing windows"));
920 		return;
921 	}
922 	curcell = us_needcell();
923 	if (curcell == NONODEPROTO) return;
924 
925 	/* in outline edit, create a point */
926 	if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
927 	{
928 		par[0] = x_("trace");
929 		par[1] = x_("add-point");
930 		us_node(2, par);
931 		return;
932 	}
933 
934 	if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
935 		centeredprimitives = FALSE;
936 	join = angledcreate = remainhighlighted = getcontents = FALSE;
937 	waitfordown = FALSE;
938 	while (count > 0)
939 	{
940 		l = estrlen(par[0]);
941 		if (namesamen(par[0], x_("remain-highlighted"), l) == 0 && l >= 1)
942 		{
943 			remainhighlighted = TRUE;
944 			count--;
945 			par++;
946 			continue;
947 		}
948 		if (namesamen(par[0], x_("contents"), l) == 0 && l >= 1)
949 		{
950 			getcontents = TRUE;
951 			count--;
952 			par++;
953 			continue;
954 		}
955 		if (namesamen(par[0], x_("wait-for-down"), l) == 0 && l >= 1)
956 		{
957 			waitfordown = TRUE;
958 			count--;
959 			par++;
960 			continue;
961 		}
962 		if ((namesamen(par[0], x_("angle"), l) == 0 ||
963 			namesamen(par[0], x_("join-angle"), l) == 0) && l >= 1)
964 		{
965 			if (namesamen(par[0], x_("join-angle"), l) == 0) join = TRUE;
966 			angledcreate = TRUE;
967 			count--;
968 			par++;
969 			if (count >= 1)
970 			{
971 				ang = atofr(par[0])*10/WHOLE;
972 				count--;
973 				par++;
974 			} else ang = ((us_curarcproto->userbits&AANGLEINC) >> AANGLEINCSH) * 10;
975 		}
976 		break;
977 	}
978 
979 	/* create a node or arc */
980 	if (count == 0)
981 	{
982 		/* if no "angle" specified, simply create a node */
983 		if (!angledcreate)
984 		{
985 			/* determine the node type being created */
986 			np = us_nodetocreate(getcontents, curcell);
987 			if (np == NONODEPROTO) return;
988 
989 			/* adjust the cursor position if selecting interactively */
990 			us_clearhighlightcount();
991 			if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
992 
993 			/* get placement angle */
994 			pangle = us_getplacementangle(np);
995 
996 			if ((us_tool->toolstate&INTERACTIVE) != 0)
997 			{
998 				us_createinit(0, 0, np, pangle, FALSE, NOGEOM, NOPORTPROTO);
999 				trackcursor(waitfordown, us_ignoreup, us_createbegin, us_dragdown,
1000 					us_stoponchar, us_dragup, TRACKDRAGGING);
1001 				if (el_pleasestop != 0) return;
1002 			}
1003 			if (us_demandxy(&xcur, &ycur)) return;
1004 			gridalign(&xcur, &ycur, 1, curcell);
1005 
1006 			/* get current cell (in case interactive placement changed the window) */
1007 			curcell = us_needcell();
1008 
1009 			/* disallow creating if lock is on */
1010 			if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1011 
1012 			/* determine size of the nodeinst */
1013 			corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1014 				centeredprimitives);
1015 			defaultnodesize(np, &pxs, &pys);
1016 
1017 			/* adjust size if technologies differ */
1018 			us_adjustfornodeincell(np, curcell, &cx, &cy);
1019 			us_adjustfornodeincell(np, curcell, &pxs, &pys);
1020 
1021 			xcur -= cx;   ycur -= cy;
1022 			newno = newnodeinst(np, xcur, xcur+pxs, ycur, ycur+pys,
1023 				pangle/3600, pangle%3600, curcell);
1024 			if (newno == NONODEINST)
1025 			{
1026 				us_abortcommand(_("Cannot create node"));
1027 				return;
1028 			}
1029 			if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1030 			if (np == gen_cellcenterprim) newno->userbits |= HARDSELECTN|NVISIBLEINSIDE; else
1031 				if (np == gen_essentialprim) newno->userbits |= HARDSELECTN;
1032 
1033 			/* copy "inheritable" attributes */
1034 			us_inheritattributes(newno);
1035 			endobjectchange((INTBIG)newno, VNODEINST);
1036 
1037 			newhigh.status = HIGHFROM;
1038 			newhigh.cell = newno->parent;
1039 			newhigh.fromgeom = newno->geom;
1040 			newhigh.fromport = NOPORTPROTO;
1041 			newhigh.frompoint = 0;
1042 			us_addhighlight(&newhigh);
1043 			return;
1044 		}
1045 
1046 		/* see if two objects are selected (and arc should connect them) */
1047 		if (!us_gettwoobjects(&fromgeom, &fromport, &togeom, &toport))
1048 		{
1049 			/* two objects highlighted: create an arc between them */
1050 			if (us_demandxy(&xcur, &ycur)) return;
1051 			gridalign(&xcur, &ycur, 1, geomparent(togeom));
1052 			if (geomparent(fromgeom) != geomparent(togeom))
1053 			{
1054 				us_abortcommand(_("Cannot run an arc between different cells"));
1055 				return;
1056 			}
1057 
1058 			if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1059 
1060 			/* run an arc from "fromgeom" to "togeom" */
1061 			if (remainhighlighted) us_pushhighlight();
1062 			us_clearhighlightcount();
1063 			if (!angledcreate) ang = 900;
1064 			ai = aconnect(fromgeom, fromport, togeom, toport, us_curarcproto,
1065 				xcur, ycur, &alt1, &alt2, &con1, &con2, ang, FALSE, TRUE);
1066 			if (remainhighlighted) us_pophighlight(FALSE);
1067 			if (ai == NOARCINST) return;
1068 
1069 			/* unless indicated, leave only one object highlighted */
1070 			if (!remainhighlighted)
1071 			{
1072 				/* if an arc was highlighted and it got broken, fix the highlight */
1073 				geom = togeom;
1074 				if (!geom->entryisnode && (geom->entryaddr.ai->userbits&DEADA) != 0)
1075 				{
1076 					geom = fromgeom;
1077 					if (!geom->entryisnode && (geom->entryaddr.ai->userbits&DEADA) != 0) return;
1078 				}
1079 
1080 				newhigh.status = HIGHFROM;
1081 				newhigh.cell = geomparent(geom);
1082 				newhigh.fromgeom = geom;
1083 				newhigh.fromport = NOPORTPROTO;
1084 				us_addhighlight(&newhigh);
1085 			}
1086 			return;
1087 		}
1088 
1089 		/* "create angle": get cursor co-ordinates */
1090 		if (us_demandxy(&xcur, &ycur)) return;
1091 		gridalign(&xcur, &ycur, 1, curcell);
1092 
1093 		/* get nodeinst from which to draw */
1094 		list = us_gethighlighted(WANTNODEINST|WANTARCINST, 0, 0);
1095 		if (list[0] == NOGEOM || list[1] != NOGEOM)
1096 		{
1097 			us_abortcommand(_("Must start new arcs from one node or arc"));
1098 			return;
1099 		}
1100 		splitpp = NOPORTPROTO;
1101 		if (list[0]->entryisnode)
1102 		{
1103 			ni = list[0]->entryaddr.ni;
1104 			high = us_getonehighlight();
1105 			if (high != NOHIGHLIGHT && (high->status&HIGHTYPE) == HIGHFROM)
1106 				splitpp = high->fromport;
1107 		} else
1108 		{
1109 			ni = us_getnodeonarcinst(&list[0], &splitpp, list[0], NOPORTPROTO, xcur, ycur, 0);
1110 			if (ni == NONODEINST)
1111 			{
1112 				us_abortcommand(_("Cannot find starting point of new arc"));
1113 				return;
1114 			}
1115 			us_endchanges(NOWINDOWPART);
1116 		}
1117 
1118 		/* ensure that cursor is in proper window */
1119 		if (ni->parent != curcell)
1120 		{
1121 			us_abortcommand(_("Cursor must be in the same cell as the highlighted node"));
1122 			return;
1123 		}
1124 		if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1125 
1126 		/* find the closest port to the cursor */
1127 		bestdist1 = bestdist2 = MAXINTBIG;
1128 		ppt = fpt = NOPORTPROTO;
1129 		for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1130 		{
1131 			if (splitpp != NOPORTPROTO && pp != splitpp) continue;
1132 			shapeportpoly(ni, pp, poly, FALSE);
1133 			k = polydistance(poly, xcur, ycur);
1134 
1135 			/* find the closest port to the cursor */
1136 			if (k < bestdist1)
1137 			{
1138 				bestdist1 = k;
1139 				ppt = pp;  /* pp is the closest port to (xcur, ycur) */
1140 			}
1141 
1142 			/* find the closest port that can connect with the current arc */
1143 			if (k < bestdist2)
1144 			{
1145 				for (i=0; pp->connects[i] != NOARCPROTO; i++)
1146 				{
1147 					if (pp->connects[i] == us_curarcproto)
1148 					{
1149 						/* can connect */
1150 						bestdist2 = k;
1151 						fpt = pp;
1152 					}
1153 				}
1154 			}
1155 		}
1156 
1157 		/* error if there is no port */
1158 		if (ppt == NOPORTPROTO)
1159 		{
1160 			us_abortcommand(_("Cannot run wires out of this node"));
1161 			return;
1162 		}
1163 
1164 		/*
1165 		 * now ppt is the closest port, and fpt is the closest port that can
1166 		 * connect with the current arc.
1167 		 */
1168 		if (fpt == NOPORTPROTO)
1169 		{
1170 			/* no arcproto of correct type: first reset all arcprotos */
1171 			for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1172 				for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1173 					ap->userbits &= ~CANCONNECT;
1174 
1175 			/* now set all arcs that can connect this node's closest port */
1176 			for(i=0; ppt->connects[i] != NOARCPROTO; i++)
1177 				ppt->connects[i]->userbits |= CANCONNECT;
1178 
1179 			/* see if current arcproto is acceptable */
1180 			if ((us_curarcproto->userbits&CANCONNECT) == 0)
1181 			{
1182 				/* search this technology for another arcproto */
1183 				for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1184 				{
1185 					if ((ap->userbits&CANCONNECT) == 0) continue;
1186 					if (getpinproto(ap) == NONODEPROTO) return;
1187 					us_setarcproto(ap, FALSE);
1188 					break;
1189 				}
1190 
1191 				/* if nothing in this technology can connect, see what can */
1192 				if (ap == NOARCPROTO && ppt->connects[0] != NOARCPROTO)
1193 				{
1194 					ap = ppt->connects[0];
1195 					if (getpinproto(ap) == NONODEPROTO) return;
1196 					us_setarcproto(ap, FALSE);
1197 				}
1198 
1199 				/* error if no acceptable arcprotos */
1200 				if (ap == NOARCPROTO)
1201 				{
1202 					us_abortcommand(_("No ports on this node"));
1203 					return;
1204 				}
1205 			}
1206 		} else ppt = fpt;
1207 		splitpp = ppt;
1208 
1209 		/* make sure the selected arc connects to this port */
1210 		wantap = us_curarcproto;
1211 		for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1212 			if (splitpp->connects[i] == us_curarcproto) break;
1213 		if (splitpp->connects[i] == NOARCPROTO)
1214 		{
1215 			/* cannot: see if anything in this technology can connect */
1216 			for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1217 				if (splitpp->connects[i]->tech == us_curarcproto->tech) break;
1218 			if (splitpp->connects[i] != NOARCPROTO) wantap = splitpp->connects[i]; else
1219 			{
1220 				/* cannot: see if anything nongeneric can connect */
1221 				for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1222 					if (splitpp->connects[i]->tech != gen_tech) break;
1223 				if (splitpp->connects[i] != NOARCPROTO) wantap = splitpp->connects[i]; else
1224 				{
1225 					/* cannot: select the first possible arcproto */
1226 					wantap = splitpp->connects[0];
1227 				}
1228 			}
1229 		}
1230 
1231 		/* turn off highlighting */
1232 		us_clearhighlightcount();
1233 
1234 		/* specify precise location for new port */
1235 		poly->xv[0] = xcur;   poly->yv[0] = ycur;   poly->count = 1;
1236 		shapeportpoly(ni, ppt, poly, 1);
1237 
1238 		/* determine pin for making the connection */
1239 		np = getpinproto(wantap);
1240 		if (np == NONODEPROTO) return;
1241 
1242 		/* get placement angle */
1243 		pangle = us_getplacementangle(np);
1244 
1245 		/* determine location of pin */
1246 		defaultnodesize(np, &pxs, &pys);
1247 		corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1248 			centeredprimitives);
1249 
1250 		/* adjust size if technologies differ */
1251 		us_adjustfornodeincell(np, curcell, &cx, &cy);
1252 		us_adjustfornodeincell(np, curcell, &pxs, &pys);
1253 		px = pxs / 2;   py = pys / 2;
1254 
1255 		/* adjust the cursor position if selecting interactively */
1256 		switch (poly->style)
1257 		{
1258 			case FILLED:
1259 			case FILLEDRECT:
1260 			case CROSSED:
1261 			case CROSS:
1262 			case BIGCROSS:
1263 			case TEXTCENT:
1264 			case TEXTTOP:
1265 			case TEXTBOT:
1266 			case TEXTLEFT:
1267 			case TEXTRIGHT:
1268 			case TEXTTOPLEFT:
1269 			case TEXTBOTLEFT:
1270 			case TEXTTOPRIGHT:
1271 			case TEXTBOTRIGHT:
1272 			case TEXTBOX:
1273 			case DISC:
1274 				getcenter(poly, &x, &y);
1275 				nx = x;   ny = y;
1276 				gridalign(&nx, &ny, 1, curcell);
1277 				if (nx != x || ny != y)
1278 				{
1279 					if (isinside(nx, ny, poly))
1280 					{
1281 						x = nx;
1282 						y = ny;
1283 					}
1284 				}
1285 				break;
1286 
1287 			default:
1288 				x = xcur;   y = ycur;
1289 				closestpoint(poly, &x, &y);
1290 				break;
1291 		}
1292 		if ((us_tool->toolstate&INTERACTIVE) != 0)
1293 		{
1294 			fromgeom = ni->geom;
1295 			us_createinit(x-px+cx, y-py+cy, np, ang, join, fromgeom, ppt);
1296 			trackcursor(waitfordown, us_ignoreup, us_createabegin, us_createadown,
1297 				us_stoponchar, us_createaup, TRACKDRAGGING);
1298 			if (el_pleasestop != 0) return;
1299 			if (us_demandxy(&xcur, &ycur)) return;
1300 			if (join)
1301 			{
1302 				us_createajoinedobject(&togeom, &toport);
1303 				if (togeom != NOGEOM)
1304 				{
1305 					if (us_figuredrawpath(fromgeom, ppt, togeom, toport, &xcur, &ycur))
1306 						return;
1307 					us_clearhighlightcount();
1308 					ai = aconnect(fromgeom, ppt, togeom, toport, wantap,
1309 						xcur, ycur, &alt1, &alt2, &con1, &con2, ang, FALSE, TRUE);
1310 					if (ai == NOARCINST) return;
1311 
1312 					/* if an arc was highlighted and it got broken, fix the highlight */
1313 					if (!togeom->entryisnode && (togeom->entryaddr.ai->userbits&DEADA) != 0)
1314 					{
1315 						togeom = fromgeom;
1316 						if (!togeom->entryisnode && (togeom->entryaddr.ai->userbits&DEADA) != 0) return;
1317 					}
1318 
1319 					newhigh.status = HIGHFROM;
1320 					newhigh.cell = geomparent(togeom);
1321 					newhigh.fromgeom = togeom;
1322 					newhigh.fromport = toport;
1323 					us_addhighlight(&newhigh);
1324 					return;
1325 				}
1326 			}
1327 			gridalign(&xcur, &ycur, 1, curcell);
1328 		}
1329 
1330 		/* determine the proper point on the polygon to draw radials */
1331 		us_getslide(ang, x-px+cx, y-py+cy, xcur, ycur, &nx, &ny);
1332 
1333 		/* adjust for the box corner */
1334 		nx -= cx;
1335 		ny -= cy;
1336 
1337 		/* handle connection if not interactive */
1338 		if ((us_tool->toolstate&INTERACTIVE) == 0)
1339 		{
1340 			/* find the object under the cursor */
1341 			if (!join) foundgeom = NOGEOM; else
1342 			{
1343 				alignment = muldiv(us_alignment_ratio, el_curlib->lambda[el_curtech->techindex], WHOLE);
1344 				foundgeom = us_getclosest(nx+px, ny+py, alignment/2, ni->parent);
1345 			}
1346 			if (foundgeom != NOGEOM)
1347 			{
1348 				/* found another object: connect to it */
1349 				fpt = ppt = NOPORTPROTO;
1350 				bestdist = bestdist2 = MAXINTBIG;
1351 				if (foundgeom->entryisnode)
1352 				{
1353 					/* find the closest port */
1354 					ni = foundgeom->entryaddr.ni;
1355 					for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1356 					{
1357 						shapeportpoly(ni, pp, poly, FALSE);
1358 						dist = polydistance(poly, xcur, ycur);
1359 
1360 						/* find the closest port to the cursor */
1361 						if (dist < bestdist)
1362 						{
1363 							bestdist = dist;
1364 							fpt = pp;
1365 						}
1366 
1367 						/* find the closest port that can connect with the current arc */
1368 						if (dist < bestdist2)
1369 						{
1370 							for (i=0; pp->connects[i] != NOARCPROTO; i++)
1371 							{
1372 								if (pp->connects[i] == wantap)
1373 								{
1374 									/* can connect */
1375 									bestdist2 = dist;
1376 									ppt = pp;
1377 								}
1378 							}
1379 						}
1380 					}
1381 					if (fpt != ppt)
1382 					{
1383 						/* the closest port cannot connect, but maybe it can with a different arc */
1384 						for(i=0; fpt->connects[i] != NOARCPROTO; i++)
1385 						{
1386 							if (fpt->connects[i]->tech == gen_tech) continue;
1387 							for(j=0; splitpp->connects[j] != NOARCPROTO; j++)
1388 							{
1389 								if (fpt->connects[i] == splitpp->connects[j]) break;
1390 							}
1391 							if (splitpp->connects[j] != NOARCPROTO) break;
1392 						}
1393 						if (fpt->connects[i] != NOARCPROTO)
1394 						{
1395 							us_setarcproto(fpt->connects[i], FALSE);
1396 							ppt = fpt;
1397 						}
1398 					}
1399 					if (ppt != NOPORTPROTO) fpt = ppt;
1400 				}
1401 				(void)aconnect(ni->geom, splitpp, foundgeom,
1402 					fpt, wantap, xcur, ycur, &alt1, &alt2, &con1, &con2, ang, TRUE, TRUE);
1403 
1404 				/* if an arc will be highlighted and it broke, fix the highlight */
1405 				if (!foundgeom->entryisnode &&
1406 					(foundgeom->entryaddr.ai->userbits&DEADA) != 0) return;
1407 
1408 				/* highlight the found object */
1409 				newhigh.status = HIGHFROM;
1410 				newhigh.cell = ni->parent;
1411 				newhigh.fromgeom = foundgeom;
1412 				newhigh.fromport = fpt;
1413 				newhigh.frompoint = 0;
1414 				us_addhighlight(&newhigh);
1415 				return;
1416 			}
1417 		}
1418 
1419 		/* determine arc width */
1420 		truewid = maxi(defaultarcwidth(wantap), us_widestarcinst(wantap, ni, ppt));
1421 		i = us_stretchtonodes(wantap, truewid, ni, ppt, xcur, ycur);
1422 		if (i > truewid) truewid = i;
1423 		wid = truewid - arcprotowidthoffset(wantap);
1424 
1425 		/* see if arc edge alignment is appropriate */
1426 		if (us_edgealignment_ratio != 0 && (x == nx || y == ny))
1427 		{
1428 			edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1429 			if (x != nx) isver = FALSE; else
1430 			{
1431 				isver = TRUE;
1432 				ny = us_alignvalue(ny + wid/2, edgealignment, &otheralign) - wid/2;
1433 			}
1434 			if (y != ny) ishor = FALSE; else
1435 			{
1436 				ishor = TRUE;
1437 				nx = us_alignvalue(nx + wid/2, edgealignment, &otheralign) - wid/2;
1438 			}
1439 
1440 			shapeportpoly(ni, ppt, poly, FALSE);
1441 			i = us_alignvalue(x + wid/2, edgealignment, &otheralign) - wid/2;
1442 			otheralign -= wid/2;
1443 			if (isinside(i, y, poly))
1444 			{
1445 				if (isver) nx = i;
1446 				x = i;
1447 			} else if (isinside(otheralign, y, poly))
1448 			{
1449 				if (isver) nx = otheralign;
1450 				x = otheralign;
1451 			}
1452 
1453 			i = us_alignvalue(y + wid/2, edgealignment, &otheralign) - wid/2;
1454 			otheralign -= wid/2;
1455 			if (isinside(x, i, poly))
1456 			{
1457 				if (ishor) ny = i;
1458 				y = i;
1459 			} else if (isinside(x, otheralign, poly))
1460 			{
1461 				if (ishor) ny = otheralign;
1462 				y = otheralign;
1463 			}
1464 		}
1465 
1466 		/* create the pin and the arcinst to it */
1467 		defaultnodesize(np, &pxs, &pys);
1468 		us_adjustfornodeincell(np, curcell, &pxs, &pys);
1469 		newno = newnodeinst(np, nx, nx+pxs, ny, ny+pys,
1470 			pangle/3600, pangle%3600, curcell);
1471 		if (newno == NONODEINST)
1472 		{
1473 			us_abortcommand(_("Cannot create pin"));
1474 			return;
1475 		}
1476 		nx += px;   ny += py;
1477 		if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1478 		endobjectchange((INTBIG)newno, VNODEINST);
1479 		if (((ppt->userbits&PORTARANGE) >> PORTARANGESH) == 180)
1480 		{
1481 			ai = us_runarcinst(ni, ppt, x, y, newno,
1482 				newno->proto->firstportproto, nx, ny, wantap, truewid);
1483 			if (ai != NOARCINST) us_reportarcscreated(0, 1, wantap->protoname, 0, x_(""));
1484 		} else
1485 		{
1486 			k = us_bottomrecurse(ni, ppt) % 3600;
1487 			if (k < 0) k += 3600;
1488 			xcur = x + mult(cosine(k), ni->highx-ni->lowx);
1489 			ycur = y + mult(sine(k), ni->highy-ni->lowy);
1490 			(void)aconnect(ni->geom, ppt, newno->geom, newno->proto->firstportproto,
1491 				wantap, xcur, ycur, &alt1, &alt2, &con1, &con2, ang, TRUE, TRUE);
1492 		}
1493 
1494 		newhigh.status = HIGHFROM;
1495 		newhigh.cell = newno->parent;
1496 		newhigh.fromgeom = newno->geom;
1497 		newhigh.fromport = NOPORTPROTO;
1498 		newhigh.frompoint = 0;
1499 		us_addhighlight(&newhigh);
1500 		return;
1501 	}
1502 
1503 	/* handle the creation of an icon */
1504 	if (namesamen(par[0], x_("icon"), l) == 0 && l >= 2)
1505 	{
1506 		/* find the icon for the current cell */
1507 		np = iconview(curcell);
1508 		if (np == NONODEPROTO)
1509 		{
1510 			us_abortcommand(_("No icon view for cell %s"),
1511 				describenodeproto(curcell));
1512 			return;
1513 		}
1514 
1515 		/* make sure there isn't already one of these */
1516 		for(ni = curcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1517 			if (ni->proto == np) break;
1518 		if (ni != NONODEINST) return;
1519 
1520 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_icon_style"));
1521 		if (var != NOVARIABLE) j = var->addr; else j = ICONSTYLEDEFAULT;
1522 		i = (j & ICONINSTLOC) >> ICONINSTLOCSH;
1523 		px = np->highx - np->lowx;
1524 		py = np->highy - np->lowy;
1525 		switch (i)
1526 		{
1527 			case 0:		/* upper-right */
1528 				lx = curcell->highx - px;
1529 				ly = curcell->highy - py;
1530 				break;
1531 			case 1:		/* upper-left */
1532 				lx = curcell->lowx;
1533 				ly = curcell->highy - py;
1534 				break;
1535 			case 2:		/* lower-right */
1536 				lx = curcell->highx - px;
1537 				ly = curcell->lowy;
1538 				break;
1539 			case 3:		/* lower-left */
1540 				lx = curcell->lowx;
1541 				ly = curcell->lowy;
1542 				break;
1543 		}
1544 		gridalign(&lx, &ly, 1, curcell);
1545 		hx = lx + px;   hy = ly + py;
1546 		ni = newnodeinst(np, lx, hx, ly, hy, 0, 0, curcell);
1547 		if (ni != NONODEINST)
1548 		{
1549 			ni->userbits |= NEXPAND;
1550 			us_inheritattributes(ni);
1551 			endobjectchange((INTBIG)ni, VNODEINST);
1552 			us_clearhighlightcount();
1553 			newhigh.status = HIGHFROM;
1554 			newhigh.cell = curcell;
1555 			newhigh.fromgeom = ni->geom;
1556 			newhigh.fromport = NOPORTPROTO;
1557 			newhigh.frompoint = 0;
1558 			us_addhighlight(&newhigh);
1559 			if (lx > el_curwindowpart->screenhx || hx < el_curwindowpart->screenlx ||
1560 				ly > el_curwindowpart->screenhy || hy < el_curwindowpart->screenly)
1561 			{
1562 				newpar[0] = x_("center-highlight");
1563 				us_window(1, newpar);
1564 			}
1565 		}
1566 		return;
1567 	}
1568 
1569 	/* handle the absolute placement option */
1570 	if (namesamen(par[0], x_("to"), l) == 0 && l >= 1)
1571 	{
1572 		/* get the location */
1573 		if (count < 3)
1574 		{
1575 			ttyputusage(x_("create to X Y"));
1576 			return;
1577 		}
1578 		nx = atola(par[1], 0);
1579 		ny = atola(par[2], 0);
1580 
1581 		/* disallow copying if lock is on */
1582 		np = us_nodetocreate(TRUE, curcell);
1583 		if (np == NONODEPROTO) return;
1584 
1585 		if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1586 
1587 		/* get placement angle */
1588 		pangle = us_getplacementangle(np);
1589 
1590 		corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1591 			centeredprimitives);
1592 		nx -= cx;   ny -= cy;
1593 		defaultnodesize(np, &pxs, &pys);
1594 		newno = newnodeinst(np, nx, nx+pxs, ny, ny+pys,
1595 			pangle/3600, pangle%3600, curcell);
1596 		if (newno == NONODEINST)
1597 		{
1598 			us_abortcommand(_("Cannot create pin"));
1599 			return;
1600 		}
1601 		if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1602 		if (np == gen_cellcenterprim) newno->userbits |= HARDSELECTN|NVISIBLEINSIDE; else
1603 			if (np == gen_essentialprim) newno->userbits |= HARDSELECTN;
1604 		endobjectchange((INTBIG)newno, VNODEINST);
1605 
1606 		us_clearhighlightcount();
1607 		newhigh.status = HIGHFROM;
1608 		newhigh.cell = newno->parent;
1609 		newhigh.fromgeom = newno->geom;
1610 		newhigh.fromport = NOPORTPROTO;
1611 		newhigh.frompoint = 0;
1612 		us_addhighlight(&newhigh);
1613 		return;
1614 	}
1615 
1616 	if (namesamen(par[0], x_("insert"), l) == 0 && l >= 2)
1617 	{
1618 		if (us_demandxy(&xcur, &ycur)) return;
1619 		gridalign(&xcur, &ycur, 1, curcell);
1620 
1621 		/* get the highlighted arc */
1622 		ai = (ARCINST *)us_getobject(VARCINST, FALSE);
1623 		if (ai == NOARCINST) return;
1624 		ap = ai->proto;
1625 
1626 		/* get the node to insert */
1627 		np = us_nodetocreate(TRUE, curcell);
1628 		if (np == NONODEPROTO) return;
1629 
1630 		/* disallow creating if lock is on */
1631 		if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1632 
1633 		/* turn off highlighting */
1634 		us_clearhighlightcount();
1635 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
1636 
1637 		/* adjust position interactively if possible */
1638 		if ((us_tool->toolstate&INTERACTIVE) != 0)
1639 		{
1640 			us_createinsinit(ai, np);
1641 			trackcursor(waitfordown, us_ignoreup, us_createinsbegin, us_createinsdown,
1642 				us_stoponchar, us_dragup, TRACKDRAGGING);
1643 			if (el_pleasestop != 0) return;
1644 		}
1645 		if (us_demandxy(&xcur, &ycur)) return;
1646 		gridalign(&xcur, &ycur, 1, curcell);
1647 
1648 		/* find two ports on this node that connect to the arc */
1649 		pp1 = pp2 = NOPORTPROTO;
1650 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1651 		{
1652 			/* make sure this port can connect to this arc */
1653 			for(i=0; pp->connects[i] != NOARCPROTO; i++)
1654 				if (pp->connects[i] == ap) break;
1655 			if (pp->connects[i] == NOARCPROTO) continue;
1656 
1657 			/* save the port */
1658 			if (pp1 == NOPORTPROTO) pp1 = pp; else
1659 				if (pp2 == NOPORTPROTO) pp2 = pp;
1660 		}
1661 
1662 		/* make sure there are two ports for connection */
1663 		if (pp1 == NOPORTPROTO)
1664 		{
1665 			us_abortcommand(_("No ports on %s node connect to %s arcs"), describenodeproto(np),
1666 				describearcproto(ap));
1667 			return;
1668 		}
1669 		if (pp2 == NOPORTPROTO) pp2 = pp1;
1670 
1671 		/* determine position of the new node */
1672 		ang = ((ai->userbits&AANGLE) >> AANGLESH) * 10;
1673 		(void)intersect(ai->end[0].xpos, ai->end[0].ypos, ang, xcur,
1674 			ycur, (ang+900)%3600, &nx, &ny);
1675 		cx = mini(ai->end[0].xpos, ai->end[1].xpos);
1676 		if (nx < cx) nx = cx;
1677 		cx = maxi(ai->end[0].xpos, ai->end[1].xpos);
1678 		if (nx > cx) nx = cx;
1679 		cy = mini(ai->end[0].ypos, ai->end[1].ypos);
1680 		if (ny < cy) ny = cy;
1681 		cy = maxi(ai->end[0].ypos, ai->end[1].ypos);
1682 		if (ny > cy) ny = cy;
1683 		defaultnodesize(np, &px, &py);
1684 		x = nx - px/2;   y = ny - py/2;
1685 
1686 		/* create the new node */
1687 		ni = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1688 		if (ni == NONODEINST)
1689 		{
1690 			us_abortcommand(_("Cannot create node %s"), describenodeproto(np));
1691 			return;
1692 		}
1693 		endobjectchange((INTBIG)ni, VNODEINST);
1694 		portposition(ni, pp1, &nx, &ny);
1695 		portposition(ni, pp2, &cx, &cy);
1696 
1697 		/* see if any rotation needs to be applied to this node */
1698 		if (pp1 != pp2)
1699 		{
1700 			k = figureangle(nx, ny, cx, cy);
1701 			if (k != ang)
1702 			{
1703 				if ((k+1800)%3600 == ang)
1704 				{
1705 					/* simple 180 degree rotation: reverse the ports */
1706 					pp = pp1;   pp1 = pp2;   pp2 = pp;
1707 				} else
1708 				{
1709 					/* complex rotation: rotate the node */
1710 					ang -= k;   if (ang < 0) ang += 3600;
1711 					startobjectchange((INTBIG)ni, VNODEINST);
1712 					modifynodeinst(ni, 0, 0, 0, 0, ang, 0);
1713 					endobjectchange((INTBIG)ni, VNODEINST);
1714 					portposition(ni, pp1, &nx, &ny);
1715 					portposition(ni, pp2, &cx, &cy);
1716 				}
1717 			}
1718 		}
1719 
1720 		/* see if node edge alignment is appropriate */
1721 		if (us_edgealignment_ratio != 0 && (ai->end[0].xpos == ai->end[1].xpos ||
1722 			ai->end[0].ypos == ai->end[1].ypos))
1723 		{
1724 			edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1725 			px = us_alignvalue(x, edgealignment, &otheralign);
1726 			py = us_alignvalue(y, edgealignment, &otheralign);
1727 			if (px != x || py != y)
1728 			{
1729 				/* shift the node and make sure the ports are still valid */
1730 				startobjectchange((INTBIG)ni, VNODEINST);
1731 				modifynodeinst(ni, px-x, py-y, px-x, py-y, 0, 0);
1732 				endobjectchange((INTBIG)ni, VNODEINST);
1733 				(void)shapeportpoly(ni, pp1, poly, FALSE);
1734 				if (!isinside(nx, ny, poly)) getcenter(poly, &nx, &ny);
1735 				(void)shapeportpoly(ni, pp2, poly, FALSE);
1736 				if (!isinside(cx, cy, poly)) getcenter(poly, &cx, &cy);
1737 			}
1738 		}
1739 
1740 		/* now save the arc information and delete it */
1741 		for(i=0; i<2; i++)
1742 		{
1743 			xp[i] = ai->end[i].xpos;
1744 			yp[i] = ai->end[i].ypos;
1745 			app[i] = ai->end[i].portarcinst->proto;
1746 			ani[i] = ai->end[i].nodeinst;
1747 		}
1748 		wid = ai->width;
1749 		bits1 = bits2 = ai->userbits;
1750 		if ((bits1&ISNEGATED) != 0)
1751 		{
1752 			if ((bits1&REVERSEEND) == 0) bits2 &= ~ISNEGATED; else
1753 				bits1 &= ~ISNEGATED;
1754 		}
1755 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1756 		if (var == NOVARIABLE) oldarcname = 0; else
1757 		{
1758 			(void)allocstring(&oldarcname, (CHAR *)var->addr, el_tempcluster);
1759 			(void)asktool(net_tool, x_("delname"), (INTBIG)oldarcname,
1760 				(INTBIG)curcell);
1761 		}
1762 		startobjectchange((INTBIG)ai, VARCINST);
1763 		(void)killarcinst(ai);
1764 
1765 		/* create the two new arcs */
1766 		newai = newarcinst(ap, wid, bits1, ani[0], app[0], xp[0], yp[0], ni, pp1, nx, ny, curcell);
1767 		if (oldarcname != 0 && newai != NOARCINST)
1768 		{
1769 			(void)asktool(net_tool, x_("setname"), (INTBIG)newai, (INTBIG)oldarcname);
1770 			var = setvalkey((INTBIG)newai, VARCINST, el_arc_name_key, (INTBIG)oldarcname, VSTRING|VDISPLAY);
1771 			if (var != NOVARIABLE)
1772 				defaulttextsize(4, var->textdescript);
1773 			efree(oldarcname);
1774 		}
1775 		if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1776 		newai = newarcinst(ap, wid, bits2, ni, pp2, cx, cy, ani[1],app[1],xp[1],yp[1], curcell);
1777 		if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1778 
1779 		/* highlight the node */
1780 		newhigh.status = HIGHFROM;
1781 		newhigh.cell = curcell;
1782 		newhigh.fromgeom = ni->geom;
1783 		newhigh.fromport = NOPORTPROTO;
1784 		newhigh.frompoint = 0;
1785 		us_addhighlight(&newhigh);
1786 		return;
1787 	}
1788 
1789 	if (namesamen(par[0], x_("breakpoint"), l) == 0 && l >= 1)
1790 	{
1791 		/* get the highlighted arc */
1792 		ai = (ARCINST *)us_getobject(VARCINST, FALSE);
1793 		if (ai == NOARCINST) return;
1794 		ap = ai->proto;
1795 
1796 		/* get the pin to insert */
1797 		np = getpinproto(ap);
1798 		if (np == NONODEPROTO)
1799 		{
1800 			us_abortcommand(_("Cannot determine pin type to insert in arc"));
1801 			return;
1802 		}
1803 		ppt = np->firstportproto;
1804 
1805 		if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1806 
1807 		/* turn off highlighting */
1808 		us_clearhighlightcount();
1809 		if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
1810 
1811 		/* adjust position interactively if possible */
1812 		if ((us_tool->toolstate&INTERACTIVE) != 0)
1813 		{
1814 			/* highlight the arc */
1815 			i = ai->width - arcwidthoffset(ai);
1816 			if (curvedarcoutline(ai, poly, OPENEDO1, i))
1817 				makearcpoly(ai->length, i, ai, poly, OPENEDO1);
1818 			if (poly->limit < poly->count+1) (void)extendpolygon(poly, poly->count+1);
1819 			poly->xv[poly->count] = poly->xv[0];
1820 			poly->yv[poly->count] = poly->yv[0];
1821 			poly->count++;
1822 			poly->desc = &us_hbox;
1823 			poly->desc->col = HIGHLIT;
1824 			us_showpoly(poly, el_curwindowpart);
1825 
1826 			/* interactively select the break location */
1827 			us_createinsinit(ai, np);
1828 			trackcursor(waitfordown, us_ignoreup, us_createinsbegin, us_createinsdown,
1829 				us_stoponchar, us_dragup, TRACKDRAGGING);
1830 
1831 			/* unhighlight the arc */
1832 			poly->desc->col = 0;
1833 			us_showpoly(poly, el_curwindowpart);
1834 			if (el_pleasestop != 0) return;
1835 		}
1836 		if (us_demandxy(&xcur, &ycur)) return;
1837 		gridalign(&xcur, &ycur, 1, curcell);
1838 
1839 		/* determine position of the new pins */
1840 		ang = ((ai->userbits&AANGLE) >> AANGLESH) * 10;
1841 		(void)intersect(ai->end[0].xpos, ai->end[0].ypos, ang, xcur, ycur, (ang+900)%3600, &nx, &ny);
1842 		cx = mini(ai->end[0].xpos, ai->end[1].xpos);
1843 		if (nx < cx) nx = cx;
1844 		cx = maxi(ai->end[0].xpos, ai->end[1].xpos);
1845 		if (nx > cx) nx = cx;
1846 		cy = mini(ai->end[0].ypos, ai->end[1].ypos);
1847 		if (ny < cy) ny = cy;
1848 		cy = maxi(ai->end[0].ypos, ai->end[1].ypos);
1849 		if (ny > cy) ny = cy;
1850 		defaultnodesize(np, &px, &py);
1851 		x = nx - px/2;   y = ny - py/2;
1852 
1853 		/* create the break pins */
1854 		ni = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1855 		if (ni == NONODEINST)
1856 		{
1857 			us_abortcommand(_("Cannot create pin %s"), describenodeproto(np));
1858 			return;
1859 		}
1860 		endobjectchange((INTBIG)ni, VNODEINST);
1861 		ni2 = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1862 		if (ni2 == NONODEINST)
1863 		{
1864 			us_abortcommand(_("Cannot create pin %s"), describenodeproto(np));
1865 			return;
1866 		}
1867 		endobjectchange((INTBIG)ni2, VNODEINST);
1868 
1869 		/* get location of connection to these pins */
1870 		portposition(ni, ppt, &nx, &ny);
1871 
1872 		/* see if edge alignment is appropriate */
1873 		if (us_edgealignment_ratio != 0 && (ai->end[0].xpos == ai->end[1].xpos ||
1874 			ai->end[0].ypos == ai->end[1].ypos))
1875 		{
1876 			edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1877 			px = us_alignvalue(x, edgealignment, &otheralign);
1878 			py = us_alignvalue(y, edgealignment, &otheralign);
1879 			if (px != x || py != y)
1880 			{
1881 				/* shift the nodes and make sure the ports are still valid */
1882 				startobjectchange((INTBIG)ni, VNODEINST);
1883 				modifynodeinst(ni, px-x, py-y, px-x, py-y, 0, 0);
1884 				endobjectchange((INTBIG)ni, VNODEINST);
1885 				startobjectchange((INTBIG)ni2, VNODEINST);
1886 				modifynodeinst(ni2, px-x, py-y, px-x, py-y, 0, 0);
1887 				endobjectchange((INTBIG)ni2, VNODEINST);
1888 				(void)shapeportpoly(ni, ppt, poly, FALSE);
1889 				if (!isinside(nx, ny, poly)) getcenter(poly, &nx, &ny);
1890 			}
1891 		}
1892 
1893 		/* now save the arc information and delete it */
1894 		for(i=0; i<2; i++)
1895 		{
1896 			xp[i] = ai->end[i].xpos;
1897 			yp[i] = ai->end[i].ypos;
1898 			app[i] = ai->end[i].portarcinst->proto;
1899 			ani[i] = ai->end[i].nodeinst;
1900 		}
1901 		wid = ai->width;
1902 		bits1 = bits2 = ai->userbits;
1903 		if ((bits1&ISNEGATED) != 0)
1904 		{
1905 			if ((bits1&REVERSEEND) == 0) bits2 &= ~ISNEGATED; else
1906 				bits1 &= ~ISNEGATED;
1907 		}
1908 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1909 		if (var == NOVARIABLE) oldarcname = 0; else
1910 		{
1911 			(void)allocstring(&oldarcname, (CHAR *)var->addr, el_tempcluster);
1912 			(void)asktool(net_tool, x_("delname"), (INTBIG)oldarcname,
1913 				(INTBIG)curcell);
1914 		}
1915 		startobjectchange((INTBIG)ai, VARCINST);
1916 		(void)killarcinst(ai);
1917 
1918 		/* create the new arcs */
1919 		newai = newarcinst(ap, wid, bits1, ani[0], app[0], xp[0], yp[0], ni, ppt, nx, ny, curcell);
1920 		if (oldarcname != 0 && newai != NOARCINST)
1921 		{
1922 			(void)asktool(net_tool, x_("setname"), (INTBIG)newai, (INTBIG)oldarcname);
1923 			var = setvalkey((INTBIG)newai, VARCINST, el_arc_name_key, (INTBIG)oldarcname, VSTRING|VDISPLAY);
1924 			if (var != NOVARIABLE)
1925 				defaulttextsize(4, var->textdescript);
1926 			efree(oldarcname);
1927 		}
1928 		if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1929 		newai = newarcinst(ap, wid, bits2, ni2, ppt, nx, ny, ani[1],app[1],xp[1],yp[1], curcell);
1930 		if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1931 		bits2 &= ~ISNEGATED;
1932 		ang = (ang + 900) % 3600;
1933 		newai = newarcinst(ap, wid, bits2, ni, ppt, nx, ny, ni2, ppt, nx, ny, curcell);
1934 		if (newai != NOARCINST)
1935 		{
1936 			endobjectchange((INTBIG)newai, VARCINST);
1937 
1938 			/* must set the angle explicitly since zero-length arcs have indeterminate angle */
1939 			newai->userbits = (newai->userbits & ~AANGLE) | (((ang+5)/10) << AANGLESH);
1940 		}
1941 
1942 		/* highlight the arc */
1943 		newhigh.status = HIGHFROM;
1944 		newhigh.cell = curcell;
1945 		newhigh.fromgeom = newai->geom;
1946 		newhigh.fromport = NOPORTPROTO;
1947 		newhigh.frompoint = 0;
1948 		us_addhighlight(&newhigh);
1949 		return;
1950 	}
1951 
1952 	ttyputbadusage(x_("create"));
1953 }
1954 
1955 #define DEBUGMERGE 1
1956 
1957 #ifdef DEBUGMERGE
1958 INTBIG us_debugmergeoffset;
1959 void us_debugwritepolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
1960 
us_debugwritepolygon(INTBIG layer,TECHNOLOGY * tech,INTBIG * x,INTBIG * y,INTBIG count)1961 void us_debugwritepolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
1962 {
1963 	REGISTER NODEPROTO *cell, *prim;
1964 	REGISTER NODEINST *ni;
1965 	REGISTER INTBIG lx, hx, ly, hy, cx, cy, *newlist;
1966 	REGISTER INTBIG i;
1967 	HIGHLIGHT high;
1968 
1969 	prim = getnodeproto(x_("metal-1-node"));
1970 	cell = us_needcell();
1971 	if (cell == NONODEPROTO) return;
1972 	lx = hx = x[0];
1973 	ly = hy = y[0];
1974 	for(i=1; i<count; i++)
1975 	{
1976 		if (x[i] < lx) lx = x[i];
1977 		if (x[i] > hx) hx = x[i];
1978 		if (y[i] < ly) ly = y[i];
1979 		if (y[i] > hy) hy = y[i];
1980 	}
1981 	cx = (lx+hx) / 2;   cy = (ly+hy) / 2;
1982 	ni = newnodeinst(prim, lx, hx, ly+us_debugmergeoffset, hy+us_debugmergeoffset, 0, 0, cell);
1983 	newlist = (INTBIG *)emalloc(count * 2 * SIZEOFINTBIG, el_tempcluster);
1984 	if (newlist == 0) return;
1985 	for(i=0; i<count; i++)
1986 	{
1987 		newlist[i*2] = x[i] - cx;
1988 		newlist[i*2+1] = y[i] - cy;
1989 	}
1990 	(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
1991 		VINTEGER|VISARRAY|((count*2)<<VLENGTHSH));
1992 	endobjectchange((INTBIG)ni, VNODEINST);
1993 	high.status = HIGHFROM;
1994 	high.fromgeom = ni->geom;
1995 	high.fromport = NOPORTPROTO;
1996 	high.frompoint = 0;
1997 	high.cell = cell;
1998 	us_addhighlight(&high);
1999 }
2000 #endif
2001 
2002 /*#define TESTMODELESS 1*/
2003 
2004 #ifdef TESTMODELESS
2005 #include "edialogs.h"
2006 /* test */
2007 static DIALOGITEM us_testdialogitems[] =
2008 {
2009  /*  1 */ {0, {172,164,196,244}, BUTTON, N_("Done")},
2010  /*  2 */ {0, {28,8,44,88}, BUTTON, N_("Button")},
2011  /*  3 */ {0, {28,100,44,216}, CHECK, N_("Check Box")},
2012  /*  4 */ {0, {56,8,72,124}, RADIO, N_("Radio 1")},
2013  /*  5 */ {0, {76,8,92,124}, RADIO, N_("Radio 2")},
2014  /*  6 */ {0, {96,8,112,124}, RADIO, N_("Radio 3")},
2015  /*  7 */ {0, {132,8,232,132}, SCROLL, x_("")},
2016  /*  8 */ {0, {4,4,20,220}, MESSAGE, N_("A Modeless Dialog")},
2017  /*  9 */ {0, {56,140,72,280}, EDITTEXT, x_("")},
2018  /* 10 */ {0, {120,8,121,288}, DIVIDELINE, x_("")},
2019  /* 11 */ {0, {93,140,109,280}, POPUP, x_("")}
2020 };
2021 static DIALOG us_testdialog = {{75,75,316,372}, x_("Modeless Dialog"), 0, 11, us_testdialogitems, 0, 0};
2022 void *us_testmodelessdia;
2023 void us_modelessdialoghitroutine(void *dia, INTBIG item);
us_modelessdialoghitroutine(void * dia,INTBIG item)2024 void us_modelessdialoghitroutine(void *dia, INTBIG item)
2025 {
2026 	if (item == 1)
2027 	{
2028 		DiaDoneDialog(us_testmodelessdia);
2029 		return;
2030 	}
2031 	if (item == 2)
2032 	{
2033 		ttyputmsg(x_("Button clicked"));
2034 		return;
2035 	}
2036 	if (item == 3)
2037 	{
2038 		DiaSetControl(us_testmodelessdia, item, 1-DiaGetControl(us_testmodelessdia, item));
2039 		return;
2040 	}
2041 	if (item == 4 || item == 5 || item == 6)
2042 	{
2043 		DiaSetControl(us_testmodelessdia, 4, 0);
2044 		DiaSetControl(us_testmodelessdia, 5, 0);
2045 		DiaSetControl(us_testmodelessdia, 6, 0);
2046 		DiaSetControl(us_testmodelessdia, item, 1);
2047 		return;
2048 	}
2049 	if (item == 9)
2050 	{
2051 		ttyputmsg(x_("Edit now is '%s'"), DiaGetText(us_testmodelessdia, 9));
2052 		return;
2053 	}
2054 	if (item == 11)
2055 	{
2056 		ttyputmsg(x_("Selected popup item %d"), DiaGetPopupEntry(us_testmodelessdia, 11));
2057 		return;
2058 	}
2059 }
2060 #endif
2061 
us_debug(INTBIG count,CHAR * par[])2062 void us_debug(INTBIG count, CHAR *par[])
2063 {
2064 	REGISTER NODEPROTO *np;
2065 	REGISTER PORTPROTO *pp;
2066 	REGISTER NODEINST *ni;
2067 	REGISTER ARCINST *ai;
2068 	REGISTER LIBRARY *lib;
2069 	REGISTER VARIABLE *var;
2070 	REGISTER INTBIG i, j, l, let1, let2, let3, filestatus;
2071 	CHAR line[200], *pt, *libname, *libfile;
2072 	extern BOOLEAN db_printerrors;
2073 
2074 	if (count == 0) return;
2075 	l = estrlen(par[0]);
2076 
2077 	/********** THESE ARE SPECIAL CASES **********/
2078 #ifdef TESTMODELESS
2079 	if (namesamen(par[0], x_("modeless"), l) == 0)
2080 	{
2081 		CHAR *popups[3];
2082 		us_testmodelessdia = DiaInitDialogModeless(&us_testdialog, us_modelessdialoghitroutine);
2083 		if (us_testmodelessdia == 0) return;
2084 		DiaInitTextDialog(us_testmodelessdia, 7, DiaNullDlogList, DiaNullDlogItem,
2085 			DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT);
2086 		DiaStuffLine(us_testmodelessdia, 7, x_("First Line"));
2087 		DiaStuffLine(us_testmodelessdia, 7, x_("Second Line"));
2088 		DiaStuffLine(us_testmodelessdia, 7, x_("Third Line"));
2089 		DiaStuffLine(us_testmodelessdia, 7, x_("Fourth Line"));
2090 		DiaStuffLine(us_testmodelessdia, 7, x_("Fifth Line"));
2091 		DiaStuffLine(us_testmodelessdia, 7, x_("Sixth Line"));
2092 		DiaStuffLine(us_testmodelessdia, 7, x_("Seventh Line"));
2093 		DiaStuffLine(us_testmodelessdia, 7, x_("Eighth Line"));
2094 		DiaStuffLine(us_testmodelessdia, 7, x_("Ninth Line"));
2095 		DiaStuffLine(us_testmodelessdia, 7, x_("Tenth Line"));
2096 		DiaSelectLine(us_testmodelessdia, 7, -1);
2097 		DiaSetText(us_testmodelessdia, 9, x_("Initial edit"));
2098 		popups[0] = x_("First popup");
2099 		popups[1] = x_("Second popup");
2100 		popups[2] = x_("Third popup");
2101 		DiaSetPopup(us_testmodelessdia, 11, 3, popups);
2102 		DiaSetControl(us_testmodelessdia, 4, 1);
2103 		return;
2104 	}
2105 #endif
2106 
2107 #if 0		/* place 1 million parts */
2108 #  define MILLIONSIZE   1000			/* square this to get number of nodes */
2109 	if (namesamen(par[0], x_("million"), l) == 0)
2110 	{
2111 		NODEPROTO *item;
2112 		extern TOOL *dr_tool, *ro_tool;
2113 		REGISTER ARCPROTO *apwire;
2114 		REGISTER PORTPROTO *ppy, *ppa;
2115 		float duration;
2116 		NODEINST *nilast;
2117 		REGISTER void *dia;
2118 		INTBIG lx, hx, ly, hy, wid, hei, maxy, maxx, nilastx, nilasty, nix, niy;
2119 
2120 		toolturnoff(dr_tool, FALSE);
2121 		toolturnoff(ro_tool, FALSE);
2122 		toolturnoff(us_tool, FALSE);
2123 		apwire = getarcproto(x_("schematic:wire"));
2124 		item = getnodeproto(x_("schematic:Off-Page"));
2125 		if (item == NONODEPROTO) return;
2126 		ppy = getportproto(item, x_("y"));
2127 		ppa = getportproto(item, x_("a"));
2128 		wid = item->highx - item->lowx;
2129 		hei = item->highy - item->lowy;
2130 		np = newnodeproto(x_("million"), el_curlib);
2131 		dia = DiaInitProgress(x_("Building..."));
2132 		if (dia == 0) return;
2133 		maxy = MILLIONSIZE;    maxx = MILLIONSIZE;
2134 		starttimer();
2135 		for(i=0; i<maxy; i++)
2136 		{
2137 			DiaSetProgress(dia, i, maxy);
2138 			nilast = NONODEINST;
2139 			for(j=0; j<maxx; j++)
2140 			{
2141 				lx = wid*j*2;   hx = lx + wid;
2142 				ly = hei*i*2;   hy = ly + hei;
2143 				ni = newnodeinst(item, lx, hx, ly, hy, 0, 0, np);
2144 				if (nilast != NONODEINST)
2145 				{
2146 					portposition(nilast, ppy, &nilastx, &nilasty);
2147 					portposition(ni, ppa, &nix, &niy);
2148 					newarcinst(apwire, 0, 0, nilast, ppy, nilastx, nilasty,
2149 						ni, ppa, nix, niy, np);
2150 				}
2151 				nilast = ni;
2152 			}
2153 		}
2154 		duration = endtimer();
2155 		ttyputmsg(x_("Took %s"), explainduration(duration));
2156 		DiaDoneProgress(dia);
2157 		toolturnon(us_tool);
2158 		toolturnon(ro_tool);
2159 		return;
2160 	}
2161 #endif
2162 
2163 #ifdef DEBUGMERGE
2164 	if (namesamen(par[0], x_("merge"), l) == 0)
2165 	{
2166 		static POLYGON *poly = NOPOLYGON;
2167 		NODEINST **nilist, *nisub;
2168 		GEOM **list;
2169 		void *merge;
2170 		INTBIG total, done, thisx, thisy, lastx, lasty;
2171 
2172 		(void)needstaticpolygon(&poly, 4, us_tool->cluster);
2173 		np = us_needcell();
2174 		if (np == NONODEPROTO) return;
2175 
2176 		/* see what is highlighted (highlighted node is subtracted) */
2177 		nisub = NONODEINST;
2178 		list = us_gethighlighted(WANTNODEINST, 0, 0);
2179 		if (list[0] != NOGEOM && list[1] == NOGEOM) nisub = list[0]->entryaddr.ni;
2180 
2181 		us_debugmergeoffset = np->highy - np->lowy +
2182 			el_curlib->lambda[el_curtech->techindex]*4;
2183 		total = 0;
2184 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2185 		{
2186 			if (ni->proto->primindex == 0) continue;
2187 			if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
2188 			if (ni == nisub) continue;
2189 			total++;
2190 		}
2191 		if (total == 0) return;
2192 		nilist = (NODEINST **)emalloc(total * (sizeof (NODEINST *)), el_tempcluster);
2193 		total = 0;
2194 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2195 		{
2196 			if (ni->proto->primindex == 0) continue;
2197 			if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
2198 			if (ni == nisub) continue;
2199 			nilist[total++] = ni;
2200 		}
2201 		done = 0;
2202 		while (done == 0)
2203 		{
2204 			done = 1;
2205 			for(i=1; i<total; i++)
2206 			{
2207 				thisx = (nilist[i]->lowx + nilist[i]->highx) / 2;
2208 				thisy = (nilist[i]->lowy + nilist[i]->highy) / 2;
2209 				lastx = (nilist[i-1]->lowx + nilist[i-1]->highx) / 2;
2210 				lasty = (nilist[i-1]->lowy + nilist[i-1]->highy) / 2;
2211 				if (lasty > thisy || (lasty == thisy && lastx <= thisx)) continue;
2212 				ni = nilist[i];   nilist[i] = nilist[i-1];   nilist[i-1] = ni;
2213 				done = 0;
2214 			}
2215 		}
2216 		merge = mergenew(us_tool->cluster);
2217 		for(l=0; l<total; l++)
2218 		{
2219 			ni = nilist[l];
2220 			j = nodepolys(ni, 0, NOWINDOWPART);
2221 			for(i=0; i<j; i++)
2222 			{
2223 				shapenodepoly(ni, i, poly);
2224 				mergeaddpolygon(merge, poly->layer, poly->tech, poly);
2225 			}
2226 		}
2227 		if (nisub != NONODEINST)
2228 		{
2229 			/* subtract this one */
2230 			j = nodepolys(nisub, 0, NOWINDOWPART);
2231 			for(i=0; i<j; i++)
2232 			{
2233 				shapenodepoly(nisub, i, poly);
2234 				mergesubpolygon(merge, poly->layer, poly->tech, poly);
2235 			}
2236 		}
2237 		mergeextract(merge, us_debugwritepolygon);
2238 		mergedelete(merge);
2239 		efree((CHAR *)nilist);
2240 		return;
2241 	}
2242 #endif
2243 
2244 #if 0		/* find floating ends of arcs */
2245 	if (namesamen(par[0], x_("show-isolated-pins"), l) == 0)
2246 	{
2247 		INTBIG fun;
2248 		HIGHLIGHT newhigh;
2249 		PORTARCINST *pi;
2250 
2251 		j = 0;
2252 		np = us_needcell();
2253 		if (np == NONODEPROTO) return;
2254 		us_clearhighlightcount();
2255 
2256 		/* look for pins sitting alone at the end of an arc */
2257 		for(ni=np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2258 		{
2259 			/* see if it is a pin */
2260 			fun = nodefunction(ni);
2261 			if (fun != NPPIN) continue;
2262 
2263 			/* ignore if it has exports on it */
2264 			if (ni->firstportexpinst != NOPORTEXPINST) continue;
2265 
2266 			/* must connect to exactly 1 arc */
2267 			if (ni->firstportarcinst == NOPORTARCINST) continue;
2268 			if (ni->firstportarcinst->nextportarcinst != NOPORTARCINST) continue;
2269 
2270 			/* highlight the node */
2271 			j++;
2272 			newhigh.status = HIGHFROM;
2273 			newhigh.cell = ni->parent;
2274 			newhigh.fromgeom = ni->geom;
2275 			newhigh.fromport = NOPORTPROTO;
2276 			newhigh.frompoint = 0;
2277 			us_addhighlight(&newhigh);
2278 		}
2279 
2280 		/* look for bus pins that don't connect to bus wires */
2281 		for(ni=np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2282 		{
2283 			/* see if it is a pin */
2284 			if (ni->proto != sch_buspinprim) continue;
2285 
2286 			/* ignore if it has exports on it */
2287 			if (ni->firstportexpinst != NOPORTEXPINST) continue;
2288 
2289 			/* must not connect to any bus arcs */
2290 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2291 				if (pi->conarcinst->proto == sch_busarc) break;
2292 			if (pi != NOPORTARCINST) continue;
2293 
2294 			/* highlight the node */
2295 			j++;
2296 			newhigh.status = HIGHFROM;
2297 			newhigh.cell = ni->parent;
2298 			newhigh.fromgeom = ni->geom;
2299 			newhigh.fromport = NOPORTPROTO;
2300 			newhigh.frompoint = 0;
2301 			us_addhighlight(&newhigh);
2302 		}
2303 		if (j == 0) ttyputmsg("No floating pins"); else
2304 			ttyputmsg("Found %ld floating pins", j);
2305 		return;
2306 	}
2307 #endif
2308 
2309 	if (namesamen(par[0], x_("postscript-schematics"), l) == 0 && l >= 2)
2310 	{
2311 		WINDOWPART *win;
2312 		win = el_curwindowpart;
2313 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2314 		{
2315 			if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
2316 
2317 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2318 			{
2319 				NODEPROTO *onp;
2320 
2321 				if (np->cellview != el_schematicview) continue;
2322 				ttyputmsg("Dumping Postscript for %s", describenodeproto(np));
2323 				onp = lib->curnodeproto;
2324 				lib->curnodeproto = np;
2325 				win->curnodeproto = np;
2326 				(void)asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)"postscript");
2327 				win->curnodeproto = onp;
2328 				lib->curnodeproto = onp;
2329 			}
2330 		}
2331 		return;
2332 	}
2333 
2334 	if (namesamen(par[0], x_("list-cells-with-universal-arcs"), l) == 0 && l >= 2)
2335 	{
2336 		LIBRARY *libwalk;
2337 		NODEPROTO *np;
2338 		ARCINST *ai;
2339 
2340 		for (libwalk = el_curlib; libwalk != NOLIBRARY; libwalk = libwalk->nextlibrary) {
2341 			for (np = libwalk->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto) {
2342 				/* check for universal arcs only in layout and schematic cells */
2343 				if (np->cellview == el_schematicview || np->cellview == el_layoutview) {
2344 					for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) {
2345 						if (ai->proto == gen_universalarc) {
2346 							ttyputmsg(x_("Found universal arc in %s, arc %s"), describenodeproto(np), describearcinst(ai));
2347 						}
2348 					}
2349 				}
2350 			}
2351 		}
2352 		return;
2353 	}
2354 
2355 	if (namesamen(par[0], x_("find-universal-arcs"), l) == 0 && l >= 2)
2356 	{
2357 		NODEPROTO *cell;
2358 		void *infstr;
2359 		ARCINST *ai;
2360 		INTBIG count;
2361 
2362 		count = 0;
2363 		cell = getcurcell();
2364 		if (cell == NONODEPROTO) {
2365 			ttyputerr(_("No current cell to search for universal arcs"));
2366 			return;
2367 		}
2368 		/* remove highlighting */
2369 		(void)asktool(us_tool, x_("clear"));
2370 
2371 		/* find any universal arcs in current cell and highlight them */
2372 		infstr = initinfstr();
2373 		for (ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) {
2374 			if (ai->proto == gen_universalarc) {
2375 				us_highlighteverywhere(ai->geom, NOPORTPROTO, 1, TRUE, getecolor("white"), FALSE);
2376 				/* JKG: this isn't quite right, but I'm not sure what is...disabling for now */
2377 				count++;
2378 			}
2379 		}
2380 		if (count == 0) ttyputmsg(_("none found"));
2381 		else ttyputmsg(x_("%d universal arcs found"), count);
2382 		return;
2383 	}
2384 
2385 	if (namesamen(par[0], x_("prepare-tsmc-io"), l) == 0 && l >= 2)
2386 	{
2387 		INTBIG total;
2388 		CHAR **filelist, libfile[200], libname[50];
2389 		LIBRARY *leflib, *gdslib, *prepfile;
2390 		extern TOOL *dr_tool;
2391 
2392 #define TSMCELECDIRECTORY x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\ELIB\\")
2393 #define TSMCGDSDIRECTORY  x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\GDS\\")
2394 #define TSMCLEFFILE       x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\LEF\\tpz872g_4lm.lef")
2395 #define TSMCPREPFILE      x_("E:\\DevelE\\Artisan\\tsmc25m4.txt")
2396 
2397 		/* turn off DRC */
2398 		toolturnoff(dr_tool, TRUE);
2399 
2400 		/* read the TSMC preparation file */
2401 		estrcpy(libname, x_("prep"));
2402 		estrcpy(libfile, TSMCPREPFILE);
2403 		prepfile = newlibrary(libname, libfile);
2404 		ttyputmsg(x_("Reading Preparation file %s"), libfile);
2405 		if (asktool(io_tool, x_("read"), (INTBIG)prepfile, (INTBIG)x_("text"), 0))
2406 		{
2407 			ttyputerr(x_("Cannot find TSMC preparation file %s"), libfile);
2408 			return;
2409 		}
2410 
2411 		/* read the LEF library with ports */
2412 		estrcpy(libname, x_("lef"));
2413 		estrcpy(libfile, TSMCLEFFILE);
2414 		leflib = newlibrary(libname, libfile);
2415 		ttyputmsg(x_("Reading LEF file %s"), libfile);
2416 		if (asktool(io_tool, x_("read"), (INTBIG)leflib, (INTBIG)x_("lef"), 0) != 0)
2417 		{
2418 			ttyputerr(x_("Cannot find LEF file %s"), libfile);
2419 			return;
2420 		}
2421 
2422 		/* create a library for the GDS files */
2423 		estrcpy(libname, x_("gds"));
2424 		estrcpy(libfile, x_("gds.elib"));
2425 		gdslib = newlibrary(libname, libfile);
2426 		selectlibrary(gdslib, TRUE);
2427 
2428 		total = filesindirectory(TSMCGDSDIRECTORY, &filelist);
2429 		for(i=0; i<total; i++)
2430 		{
2431 			if (filelist[i][0] == '.') continue;
2432 
2433 			/* read the GDS file */
2434 			eraselibrary(gdslib);
2435 			estrcpy(libfile, TSMCGDSDIRECTORY);
2436 			estrcat(libfile, filelist[i]);
2437 			(void)reallocstring(&gdslib->libfile, libfile, gdslib->cluster);
2438 			ttyputmsg(x_("Reading GDS file %s"), libfile);
2439 			if (asktool(io_tool, x_("read"), (INTBIG)gdslib, (INTBIG)x_("gds"), 0) != 0) break;
2440 
2441 			/* synchronize the ports */
2442 			us_portsynchronize(leflib);
2443 
2444 			/* mark all cells as part of a "cell library" */
2445 			for(np = gdslib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2446 				np->userbits |= INCELLLIBRARY;
2447 
2448 			/* write the Electric library */
2449 			estrcpy(libfile, TSMCELECDIRECTORY);
2450 			estrcat(libfile, filelist[i]);
2451 			j = estrlen(libfile);
2452 			if (namesame(&libfile[j-4], x_(".gds")) == 0) libfile[j-4] = 0;
2453 			(void)reallocstring(&gdslib->libfile, libfile, gdslib->cluster);
2454 			gdslib->userbits |= READFROMDISK;
2455 			if (asktool(io_tool, x_("write"), (INTBIG)gdslib, (INTBIG)x_("binary")) != 0) break;
2456 		}
2457 		prepfile->userbits &= ~(LIBCHANGEDMAJOR|LIBCHANGEDMINOR);
2458 		leflib->userbits &= ~(LIBCHANGEDMAJOR|LIBCHANGEDMINOR);
2459 		return;
2460 	}
2461 
2462 	if (namesamen(par[0], x_("erase-bits"), l) == 0 && l >= 2)
2463 	{
2464 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2465 		{
2466 			/* clear the library bits */
2467 			lib->temp1 = lib->temp2 = 0;
2468 			lib->userbits &= (LIBCHANGEDMAJOR | LIBCHANGEDMINOR | LIBUNITS);
2469 
2470 			/* look at every cell in the library */
2471 			for(np=lib->firstnodeproto; np!=NONODEPROTO; np=np->nextnodeproto)
2472 			{
2473 				/* clear the node prototype bits */
2474 				np->temp1 = np->temp2 = 0;
2475 				np->userbits &= WANTNEXPAND;
2476 
2477 				/* clear the port prototype bits */
2478 				for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2479 				{
2480 					pp->temp1 = pp->temp2 = 0;
2481 					pp->userbits &= (STATEBITS|PORTANGLE|PORTARANGE);
2482 				}
2483 
2484 				/* clear the node instance bits */
2485 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2486 				{
2487 					ni->temp1 = ni->temp2 = 0;
2488 					ni->userbits &= NEXPAND;
2489 
2490 					/* compute WIPED bit on node instance */
2491 					ni->userbits |= us_computewipestate(ni);
2492 				}
2493 
2494 				/* clear the arc instance bits */
2495 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2496 				{
2497 					ai->temp1 = ai->temp2 = 0;
2498 					ai->userbits &= (FIXED|FIXANG|ISNEGATED|NOEXTEND|NOTEND0|NOTEND1|REVERSEEND|CANTSLIDE);
2499 					determineangle(ai);
2500 					(void)setshrinkvalue(ai, FALSE);
2501 				}
2502 			}
2503 		}
2504 		ttyputmsg(x_("All tool words reset"));
2505 		return;
2506 	}
2507 
2508 	if (namesamen(par[0], x_("label-cell"), l) == 0 && l >= 1)
2509 	{
2510 		np = us_needcell();
2511 		if (np == NONODEPROTO) return;
2512 		us_clearhighlightcount();
2513 		let1 = 'A';   let2 = let3 = 0;
2514 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2515 		{
2516 			line[0] = (CHAR)let1;   line[1] = (CHAR)let2;
2517 			line[2] = (CHAR)let3;   line[3] = 0;
2518 			var = getvalkey((INTBIG)ni, VNODEINST, -1, el_node_name_key);
2519 			if (var != NOVARIABLE) continue;
2520 			var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)line,
2521 				VSTRING|VDISPLAY);
2522 			if (var != NOVARIABLE)
2523 				defaulttextsize(3, var->textdescript);
2524 			let1++;
2525 			if (let1 > 'Z')
2526 			{
2527 				let1 = 'A';
2528 				if (let2 == 0) let2 = 'A'; else let2++;
2529 				if (let2 > 'Z')
2530 				{
2531 					let2 = 'A';
2532 					if (let3 == 0) let3 = 'A'; else let3++;
2533 				}
2534 			}
2535 		}
2536 		i = 1;
2537 		for(ai = np->firstarcinst; ai != NOARCINST;
2538 			ai = ai->nextarcinst)
2539 		{
2540 			(void)esnprintf(line, 200, x_("%ld"), i++);
2541 			var = getvalkey((INTBIG)ai, VARCINST, -1, el_arc_name_key);
2542 			if (var != NOVARIABLE) continue;
2543 			var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)line,
2544 				VSTRING|VDISPLAY);
2545 			if (var != NOVARIABLE)
2546 				defaulttextsize(4, var->textdescript);
2547 		}
2548 		us_redisplay(el_curwindowpart);
2549 		return;
2550 	}
2551 
2552 	/********** THESE ARE STANDARD **********/
2553 
2554 	if (namesamen(par[0], x_("arena"), l) == 0 && l >= 1)
2555 	{
2556 		if (count > 1) db_printclusterarena(par[1]); else
2557 			db_printclusterarena(x_(""));
2558 		return;
2559 	}
2560 
2561 	if (namesamen(par[0], x_("check-database"), l) == 0 && l >= 1)
2562 	{
2563 		if (count > 1 && namesamen(par[1], x_("verbose"), estrlen(par[1])) == 0)
2564 			us_checkdatabase(TRUE); else
2565 				us_checkdatabase(FALSE);
2566 		return;
2567 	}
2568 
2569 	if (namesamen(par[0], x_("translate"), l) == 0 && l >= 1)
2570 	{
2571 		us_translationdlog();
2572 		return;
2573 	}
2574 
2575 	if (namesamen(par[0], x_("dialog-edit"), l) == 0 && l >= 1)
2576 	{
2577 		us_dialogeditor();
2578 		return;
2579 	}
2580 
2581 	if (namesamen(par[0], x_("examine-options"), l) == 0 && l >= 2)
2582 	{
2583 		libname = us_tempoptionslibraryname();
2584 		libfile = optionsfilepath();
2585 		filestatus = fileexistence(truepath(libfile));
2586 		if (filestatus == 1 || filestatus == 3)
2587 		{
2588 			lib = newlibrary(libname, libfile);
2589 			if (lib == NOLIBRARY) return;
2590 			(void)asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)x_("binary"));
2591 			(void)asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("text"));
2592 			killlibrary(lib);
2593 		}
2594 		return;
2595 	}
2596 
2597 	if (namesamen(par[0], x_("freeze-user-interface"), l) == 0 && l >= 1)
2598 	{
2599 		j = l = 0;
2600 		for(i=0; i<us_tool->numvar; i++)
2601 		{
2602 			var = &us_tool->firstvar[i];
2603 			pt = makename(var->key);
2604 			if (namesamen(pt, x_("USER_binding_"), 13) == 0)
2605 			{
2606 				if (namesame(pt, x_("USER_binding_menu")) == 0) continue;
2607 				var->type &= ~VDONTSAVE;
2608 				j++;
2609 			} else if (namesamen(pt, x_("USER_macro_"), 11) == 0)
2610 			{
2611 				var->type &= ~VDONTSAVE;
2612 
2613 				/*
2614 				 * when saving macros to disk, must erase entry 2, which
2615 				 * is the address of the parsing structures: these cannot
2616 				 * be valid when read back in.
2617 				 */
2618 				setindkey((INTBIG)us_tool, VTOOL, var->key, 2, (INTBIG)x_(""));
2619 				l++;
2620 			}
2621 		}
2622 		ttyputmsg(x_("Made %ld macros and %ld bindings permanent"), l, j);
2623 		return;
2624 	}
2625 
2626 	if (namesamen(par[0], x_("internal-errors"), l) == 0 && l >= 1)
2627 	{
2628 		db_printerrors = !db_printerrors;
2629 		ttyputmsg(x_("Internal database errors will %sbe printed"),
2630 			(db_printerrors ? x_("") : x_("not ")));
2631 		return;
2632 	}
2633 
2634 	if (namesamen(par[0], x_("namespace"), l) == 0 && l >= 1)
2635 	{
2636 		ttyputmsg(x_("%ld names in global namespace:"), el_numnames);
2637 		for(i=0; i<el_numnames; i++) ttyputmsg(x_("'%s'"), el_namespace[i]);
2638 		return;
2639 	}
2640 
2641 	if (namesamen(par[0], x_("options-changed"), l) == 0 && l >= 1)
2642 	{
2643 		explainoptionchanges(-1, 0);
2644 		return;
2645 	}
2646 
2647 	if (namesamen(par[0], x_("rtree"), l) == 0 && l >= 2)
2648 	{
2649 		np = us_needcell();
2650 		if (np == NONODEPROTO) return;
2651 		ttyputmsg(x_("R-tree for cell %s (nodes hold from %d to %d entries)"),
2652 			describenodeproto(np), MINRTNODESIZE, MAXRTNODESIZE);
2653 		db_printrtree(NORTNODE, np->rtree, 0);
2654 		return;
2655 	}
2656 
2657 	if (namesamen(par[0], x_("undo"), l) == 0 && l >= 1)
2658 	{
2659 		db_undodlog();
2660 		return;
2661 	}
2662 
2663 	ttyputbadusage(x_("debug"));
2664 }
2665 
us_defarc(INTBIG count,CHAR * par[])2666 void us_defarc(INTBIG count, CHAR *par[])
2667 {
2668 	REGISTER CHAR *aname, *pt;
2669 	REGISTER BOOLEAN negate;
2670 	REGISTER INTBIG l, i, wid, style, bits;
2671 	REGISTER ARCPROTO *ap;
2672 	REGISTER PORTPROTO *pp;
2673 	REGISTER NODEPROTO *np;
2674 	extern COMCOMP us_defarcsp, us_defarcnotp, us_defarcwidp, us_defarcpinp, us_defarcangp;
2675 	REGISTER VARIABLE *var;
2676 	REGISTER void *infstr;
2677 
2678 	if (count == 0)
2679 	{
2680 		count = ttygetparam(_("Arc prototype: "), &us_defarcsp, MAXPARS, par);
2681 		if (count == 0)
2682 		{
2683 			us_abortedmsg();
2684 			return;
2685 		}
2686 	}
2687 
2688 	/* get arc prototype name */
2689 	if (estrcmp(par[0], x_("*")) == 0)
2690 	{
2691 		ap = NOARCPROTO;
2692 		aname = x_("all");
2693 	} else
2694 	{
2695 		ap = getarcproto(par[0]);
2696 		if (ap == NOARCPROTO)
2697 		{
2698 			us_abortcommand(_("Unknown arc prototype: %s"), par[0]);
2699 			return;
2700 		}
2701 		aname = ap->protoname;
2702 	}
2703 
2704 	if (count <= 1)
2705 	{
2706 		/* get style to report */
2707 		if (ap != NOARCPROTO)
2708 		{
2709 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2710 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2711 		} else
2712 		{
2713 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2714 			if (var != NOVARIABLE) style = var->addr; else style = -1;
2715 			if (style == -1)
2716 			{
2717 				ttyputmsg(_("No overriding defaults set for arcs"));
2718 				return;
2719 			}
2720 		}
2721 		infstr = initinfstr();
2722 		formatinfstr(infstr, _("%s arcs drawn "), aname);
2723 		if ((style&WANTFIX) != 0) addstringtoinfstr(infstr, _("rigid")); else
2724 		{
2725 			addstringtoinfstr(infstr, _("nonrigid, "));
2726 			if ((style&WANTFIXANG) == 0) addstringtoinfstr(infstr, _("not fixed angle, ")); else
2727 				addstringtoinfstr(infstr, _("fixed angle, "));
2728 			if ((style&WANTCANTSLIDE) != 0) addstringtoinfstr(infstr, _("nonslidable")); else
2729 				addstringtoinfstr(infstr, _("slidable"));
2730 		}
2731 		if ((style&WANTDIRECTIONAL) != 0) addstringtoinfstr(infstr, _(", directional"));
2732 		if ((style&WANTNEGATED) != 0) addstringtoinfstr(infstr, _(", negated"));
2733 		addstringtoinfstr(infstr, x_(", "));
2734 		if ((style&WANTNOEXTEND) != 0) addstringtoinfstr(infstr, _("not ends-extended")); else
2735 			addstringtoinfstr(infstr, _("ends-extended"));
2736 		if (ap != NOARCPROTO)
2737 			formatinfstr(infstr, _(", width %s, angle %ld"),
2738 				latoa(defaultarcwidth(ap)-arcprotowidthoffset(ap), 0),
2739 					(ap->userbits&AANGLEINC) >> AANGLEINCSH);
2740 		ttyputmsg(x_("%s"), returninfstr(infstr));
2741 		return;
2742 	}
2743 
2744 	l = estrlen(pt = par[1]);
2745 	negate = FALSE;
2746 
2747 	if (namesamen(pt, x_("not"), l) == 0 && l >= 2)
2748 	{
2749 		if (count <= 2)
2750 		{
2751 			count = ttygetparam(_("Defarc option: "), &us_defarcnotp, MAXPARS-2, &par[2])+2;
2752 			if (count == 2)
2753 			{
2754 				us_abortedmsg();
2755 				return;
2756 			}
2757 		}
2758 		count--;
2759 		par++;
2760 		negate = TRUE;
2761 		l = estrlen(pt = par[1]);
2762 	}
2763 
2764 	if (namesamen(pt, x_("default"), l) == 0 && l >= 2)
2765 	{
2766 		if (ap != NOARCPROTO)
2767 		{
2768 			(void)delvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey);
2769 			ttyputverbose(M_("%s arcs drawn in default style"), describearcproto(ap));
2770 			return;
2771 		}
2772 		(void)delvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey);
2773 		ttyputverbose(M_("All arcs drawn in default style"));
2774 		return;
2775 	}
2776 
2777 	if ((namesamen(pt, x_("manhattan"), l) == 0 || namesamen(pt, x_("fixed-angle"), l) == 0) && l >= 1)
2778 	{
2779 		if (namesamen(pt, x_("manhattan"), l) == 0)
2780 			ttyputmsg(_("It is now proper to use 'defarc fixed-angle' instead of 'defarc manhattan'"));
2781 		if (ap != NOARCPROTO)
2782 		{
2783 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2784 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2785 			if (negate) style &= ~WANTFIXANG; else style |= WANTFIXANG;
2786 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2787 		} else
2788 		{
2789 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2790 			if (var != NOVARIABLE) style = var->addr; else style = 0;
2791 			if (negate) style &= ~WANTFIXANG; else style |= WANTFIXANG;
2792 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2793 		}
2794 		if (negate) ttyputverbose(M_("%s arcs drawn not fixed-angle"), aname); else
2795 			ttyputverbose(M_("%s arcs drawn fixed-angle"), aname);
2796 		return;
2797 	}
2798 
2799 	if (namesamen(pt, x_("rigid"), l) == 0 && l >= 1)
2800 	{
2801 		if (ap != NOARCPROTO)
2802 		{
2803 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2804 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2805 			if (negate) style &= ~WANTFIX; else style |= WANTFIX;
2806 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2807 		} else
2808 		{
2809 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2810 			if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2811 			if (negate) style &= ~WANTFIX; else style |= WANTFIX;
2812 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2813 		}
2814 		if (negate) ttyputverbose(M_("%s arcs drawn un-rigid"), aname); else
2815 			ttyputverbose(M_("%s arcs drawn rigid"), aname);
2816 		return;
2817 	}
2818 
2819 	if (namesamen(pt, x_("directional"), l) == 0 && l >= 2)
2820 	{
2821 		if (ap != NOARCPROTO)
2822 		{
2823 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2824 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2825 			if (negate) style &= ~WANTDIRECTIONAL; else
2826 				style |= WANTDIRECTIONAL;
2827 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2828 		} else
2829 		{
2830 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2831 			if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2832 			if (negate) style &= ~WANTDIRECTIONAL; else
2833 				style |= WANTDIRECTIONAL;
2834 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2835 		}
2836 		if (negate) ttyputverbose(M_("%s arcs drawn nondirectional"), aname); else
2837 			ttyputverbose(M_("%s arcs drawn directional"), aname);
2838 		return;
2839 	}
2840 
2841 	if (namesamen(pt, x_("slide"), l) == 0 && l >= 1)
2842 	{
2843 		if (ap != NOARCPROTO)
2844 		{
2845 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2846 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2847 			if (negate) style &= ~WANTCANTSLIDE; else
2848 				style |= WANTCANTSLIDE;
2849 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2850 		} else
2851 		{
2852 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2853 			if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2854 			if (negate) style &= ~WANTCANTSLIDE; else
2855 				style |= WANTCANTSLIDE;
2856 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2857 		}
2858 		if (negate) ttyputverbose(M_("%s arcs can not slide in their ports"), aname); else
2859 			ttyputverbose(M_("%s arcs can slide in their ports"), aname);
2860 		return;
2861 	}
2862 
2863 	if (namesamen(pt, x_("negated"), l) == 0 && l >= 2)
2864 	{
2865 		if (ap != NOARCPROTO)
2866 		{
2867 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2868 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2869 			if (negate) style &= ~WANTNEGATED; else style |= WANTNEGATED;
2870 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2871 		} else
2872 		{
2873 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2874 			if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2875 			if (negate) style &= ~WANTNEGATED; else style |= WANTNEGATED;
2876 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2877 		}
2878 		if (negate) ttyputverbose(M_("%s arcs drawn un-negated"), aname); else
2879 			ttyputverbose(M_("%s arcs drawn negated"), aname);
2880 		return;
2881 	}
2882 
2883 	if (namesamen(pt, x_("ends-extend"), l) == 0 && l >= 1)
2884 	{
2885 		if (ap != NOARCPROTO)
2886 		{
2887 			var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2888 			if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2889 			if (negate) style |= WANTNOEXTEND; else style &= ~WANTNOEXTEND;
2890 			(void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2891 		} else
2892 		{
2893 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2894 			if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2895 			if (negate) style |= WANTNOEXTEND; else style &= ~WANTNOEXTEND;
2896 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2897 		}
2898 		if (negate) ttyputverbose(M_("%s arcs drawn with ends not extended"), aname); else
2899 			ttyputverbose(M_("%s arcs drawn with ends extended by half-width"), aname);
2900 		return;
2901 	}
2902 
2903 	if (namesamen(pt, x_("width"), l) == 0 && l >= 1)
2904 	{
2905 		if (ap == NOARCPROTO)
2906 		{
2907 			us_abortcommand(_("Default width requires specific arc prototypes"));
2908 			return;
2909 		}
2910 		if (count <= 2)
2911 		{
2912 			count = ttygetparam(_("Width: "), &us_defarcwidp, MAXPARS-2, &par[2]) + 2;
2913 			if (count == 2)
2914 			{
2915 				us_abortedmsg();
2916 				return;
2917 			}
2918 		}
2919 		pt = par[2];
2920 		i = atola(pt, 0);
2921 		if (i&1) i++;
2922 		if (i < 0)
2923 		{
2924 			us_abortcommand(_("Width must not be negative"));
2925 			return;
2926 		}
2927 		wid = arcprotowidthoffset(ap) + i;
2928 		wid = wid * WHOLE / el_curlib->lambda[ap->tech->techindex];
2929 		(void)setvalkey((INTBIG)ap, VARCPROTO, el_arc_width_default_key, wid, VINTEGER);
2930 		ttyputverbose(M_("%s arcs default to %s wide"), aname, latoa(i, 0));
2931 		return;
2932 	}
2933 
2934 	if (namesamen(pt, x_("angle"), l) == 0 && l >= 1)
2935 	{
2936 		if (ap == NOARCPROTO)
2937 		{
2938 			us_abortcommand(_("Default angle increment requires specific arc prototypes"));
2939 			return;
2940 		}
2941 		if (count <= 2)
2942 		{
2943 			count = ttygetparam(_("Angle: "), &us_defarcangp, MAXPARS-2, &par[2]) + 2;
2944 			if (count == 2)
2945 			{
2946 				us_abortedmsg();
2947 				return;
2948 			}
2949 		}
2950 		pt = par[2];
2951 		i = eatoi(pt) % 360;
2952 		if (i < 0)
2953 		{
2954 			us_abortcommand(_("Angle increment must not be negative"));
2955 			return;
2956 		}
2957 		bits = (ap->userbits & ~AANGLEINC) | (i << AANGLEINCSH);
2958 		(void)setval((INTBIG)ap, VARCPROTO, x_("userbits"), bits, VINTEGER);
2959 		ttyputverbose(M_("%s arcs will run at %ld degree angle increments"), aname, i);
2960 		return;
2961 	}
2962 
2963 	if (namesamen(pt, x_("pin"), l) == 0 && l >= 1)
2964 	{
2965 		if (ap == NOARCPROTO)
2966 		{
2967 			us_abortcommand(_("Default pin requires specific arc prototypes"));
2968 			return;
2969 		}
2970 		if (count <= 2)
2971 		{
2972 			count = ttygetparam(_("Pin: "), &us_defarcpinp, MAXPARS-2, &par[2]) + 2;
2973 			if (count == 2)
2974 			{
2975 				us_abortedmsg();
2976 				return;
2977 			}
2978 		}
2979 		np = getnodeproto(par[2]);
2980 		if (np == NONODEPROTO)
2981 		{
2982 			us_abortcommand(_("Cannot find primitive %s"), par[2]);
2983 			return;
2984 		}
2985 		pp = np->firstportproto;
2986 		for(i=0; pp->connects[i] != NOARCPROTO; i++)
2987 			if (pp->connects[i] == ap) break;
2988 		if (pp->connects[i] == NOARCPROTO)
2989 		{
2990 			us_abortcommand(_("Cannot: the %s node must connect to %s arcs on its first port (%s)"),
2991 				describenodeproto(np), aname, pp->protoname);
2992 			return;
2993 		}
2994 		(void)setval((INTBIG)ap, VARCPROTO, x_("ARC_Default_Pin"), (INTBIG)np, VNODEPROTO|VDONTSAVE);
2995 		ttyputverbose(M_("Default pins for arc %s will be %s"), aname, describenodeproto(np));
2996 		return;
2997 	}
2998 
2999 	ttyputbadusage(x_("defarc"));
3000 }
3001 
us_defnode(INTBIG count,CHAR * par[])3002 void us_defnode(INTBIG count, CHAR *par[])
3003 {
3004 	REGISTER CHAR *pp, *nname;
3005 	BOOLEAN negated;
3006 	REGISTER INTBIG l, pangle;
3007 	REGISTER INTBIG i, j;
3008 	INTBIG plx, ply, phx, phy, nodesize[2];
3009 	REGISTER VARIABLE *var;
3010 	REGISTER NODEPROTO *np, *onp;
3011 	extern COMCOMP us_defnodesp, us_defnodexsp, us_defnodeysp;
3012 
3013 	if (count == 0)
3014 	{
3015 		count = ttygetparam(_("Node prototype: "), &us_defnodesp, MAXPARS, par);
3016 		if (count == 0)
3017 		{
3018 			us_abortedmsg();
3019 			return;
3020 		}
3021 	}
3022 
3023 	/* get node prototype name */
3024 	if (estrcmp(par[0], x_("*")) == 0)
3025 	{
3026 		np = NONODEPROTO;
3027 		nname = _("All complex");
3028 	} else
3029 	{
3030 		np = getnodeproto(par[0]);
3031 		if (np == NONODEPROTO)
3032 		{
3033 			us_abortcommand(_("Unknown node prototype: %s"), par[0]);
3034 			return;
3035 		}
3036 		nname = describenodeproto(np);
3037 	}
3038 
3039 	if (count <= 1)
3040 	{
3041 		ttyputusage(x_("defnode OPTIONS"));
3042 		return;
3043 	}
3044 
3045 	l = estrlen(pp = par[1]);
3046 
3047 	/* handle negation */
3048 	if (namesamen(pp, x_("not"), l) == 0 && l >= 1)
3049 	{
3050 		negated = TRUE;
3051 		count--;
3052 		par++;
3053 		l = estrlen(pp = par[1]);
3054 	} else negated = FALSE;
3055 
3056 	if (namesamen(pp, x_("from-cell-library"), l) == 0)
3057 	{
3058 		if (np != NONODEPROTO && np->primindex != 0)
3059 		{
3060 			us_abortcommand(_("Cell library marking can only be done for cells"));
3061 			return;
3062 		}
3063 		for(onp = el_curlib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3064 		{
3065 			if (np != NONODEPROTO && np != onp) continue;
3066 			if (!negated)
3067 			{
3068 				if ((onp->userbits&INCELLLIBRARY) != 0)
3069 				{
3070 					ttyputverbose(M_("Cell %s is already part of a cell library"),
3071 						describenodeproto(onp));
3072 				} else
3073 				{
3074 					ttyputverbose(M_("Cell %s is now part of a cell library"),
3075 						describenodeproto(onp));
3076 				}
3077 				(void)setval((INTBIG)onp, VNODEPROTO, x_("userbits"),
3078 					onp->userbits | INCELLLIBRARY, VINTEGER);
3079 			} else
3080 			{
3081 				if ((onp->userbits&INCELLLIBRARY) == 0)
3082 				{
3083 					ttyputverbose(M_("Cell %s is already not part of a cell library"),
3084 						describenodeproto(onp));
3085 				} else
3086 				{
3087 					ttyputverbose(M_("Cell %s is now not part of a cell library"),
3088 						describenodeproto(onp));
3089 				}
3090 				(void)setval((INTBIG)onp, VNODEPROTO, x_("userbits"),
3091 					onp->userbits & ~INCELLLIBRARY, VINTEGER);
3092 			}
3093 		}
3094 		return;
3095 	}
3096 
3097 	if (namesamen(pp, x_("check-dates"), l) == 0 && l >= 2)
3098 	{
3099 		if (np != NONODEPROTO)
3100 		{
3101 			us_abortcommand(_("Date checking must be done for all cells (*)"));
3102 			return;
3103 		}
3104 		if (!negated)
3105 		{
3106 			if ((us_useroptions&CHECKDATE) != 0)
3107 				ttyputverbose(M_("Cell revision dates already being checked")); else
3108 					ttyputverbose(M_("Cell revision date errors will be identified"));
3109 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3110 				us_useroptions | CHECKDATE, VINTEGER);
3111 		} else
3112 		{
3113 			if ((us_useroptions&CHECKDATE) == 0)
3114 				ttyputverbose(M_("Cell revision dates already being ignored")); else
3115 					ttyputverbose(M_("Cell revision date errors will be ignored"));
3116 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3117 				us_useroptions & ~CHECKDATE, VINTEGER);
3118 		}
3119 		return;
3120 	}
3121 
3122 	if (namesamen(pp, x_("centered-primitives"), l) == 0 && l >= 2)
3123 	{
3124 		if (np != NONODEPROTO)
3125 		{
3126 			us_abortcommand(_("Primitive centering must be done for all nodes (*)"));
3127 			return;
3128 		}
3129 		if (!negated)
3130 		{
3131 			if ((us_useroptions&CENTEREDPRIMITIVES) != 0)
3132 				ttyputverbose(M_("Primitives are already being placed by their center")); else
3133 					ttyputverbose(M_("Primitives will be placed by their center"));
3134 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3135 				us_useroptions | CENTEREDPRIMITIVES, VINTEGER);
3136 		} else
3137 		{
3138 			if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
3139 				ttyputverbose(M_("Primitives are already being placed by edges")); else
3140 					ttyputverbose(M_("Primitives will be placed by edges"));
3141 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3142 				us_useroptions & ~CENTEREDPRIMITIVES, VINTEGER);
3143 		}
3144 		return;
3145 	}
3146 
3147 	if (namesamen(pp, x_("copy-ports"), l) == 0 && l >= 2)
3148 	{
3149 		if (np != NONODEPROTO)
3150 		{
3151 			us_abortcommand(_("Port copying must be done for all nodes (*)"));
3152 			return;
3153 		}
3154 		if (!negated)
3155 		{
3156 			if ((us_useroptions&DUPCOPIESPORTS) != 0)
3157 				ttyputverbose(M_("Ports are already being copied by duplicate/array/yanknode")); else
3158 					ttyputverbose(M_("Ports will be copied by duplicate/array/yanknode"));
3159 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3160 				us_useroptions | DUPCOPIESPORTS, VINTEGER);
3161 		} else
3162 		{
3163 			if ((us_useroptions&DUPCOPIESPORTS) == 0)
3164 				ttyputverbose(M_("Ports are already not being copied by duplicate/array/yanknode")); else
3165 					ttyputverbose(M_("Ports will not be copied by duplicate/array/yanknode"));
3166 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3167 				us_useroptions & ~DUPCOPIESPORTS, VINTEGER);
3168 		}
3169 		return;
3170 	}
3171 
3172 	if (namesamen(pp, x_("alterable"), l) == 0 && l >= 1)
3173 	{
3174 		if (np != NONODEPROTO)
3175 		{
3176 			/* set alterability of cells */
3177 			if (!negated)
3178 			{
3179 				if ((np->userbits&NPLOCKED) == 0)
3180 				{
3181 					ttyputverbose(M_("Contents of cell %s are already able to be freely altered"),
3182 						describenodeproto(np));
3183 				} else
3184 				{
3185 					ttyputverbose(M_("Contents of cell %s may now be freely edited"),
3186 						describenodeproto(np));
3187 				}
3188 				(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3189 					np->userbits & ~NPLOCKED, VINTEGER);
3190 			} else
3191 			{
3192 				if ((np->userbits&NPLOCKED) != 0)
3193 				{
3194 					ttyputverbose(M_("Contents of cell %s are already locked"),
3195 						describenodeproto(np));
3196 				} else
3197 				{
3198 					ttyputverbose(M_("Contents of cell %s will not be allowed to change"),
3199 						describenodeproto(np));
3200 				}
3201 				(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3202 					np->userbits | NPLOCKED, VINTEGER);
3203 			}
3204 		} else
3205 		{
3206 			us_abortcommand(_("Must set alterability for a specific cell"));
3207 		}
3208 		return;
3209 	}
3210 
3211 	if (namesamen(pp, x_("instances-locked"), l) == 0 && l >= 1)
3212 	{
3213 		if (np == NONODEPROTO)
3214 		{
3215 			us_abortcommand(_("Cell instance locking cannot be done for all prototypes (*)"));
3216 			return;
3217 		}
3218 
3219 		/* set alterability of cell instances */
3220 		if (negated)
3221 		{
3222 			if ((np->userbits&NPILOCKED) == 0)
3223 			{
3224 				ttyputverbose(M_("Instances in cell %s are already able to be freely altered"),
3225 					describenodeproto(np));
3226 			} else
3227 			{
3228 				ttyputverbose(M_("Instances in cell %s may now be freely edited"),
3229 					describenodeproto(np));
3230 			}
3231 			(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3232 				np->userbits & ~NPILOCKED, VINTEGER);
3233 		} else
3234 		{
3235 			if ((np->userbits&NPILOCKED) != 0)
3236 			{
3237 				ttyputverbose(M_("Instances in cell %s are already locked"),
3238 					describenodeproto(np));
3239 			} else
3240 			{
3241 				ttyputverbose(M_("Instances in cell %s will not be allowed to change"),
3242 					describenodeproto(np));
3243 			}
3244 			(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3245 				np->userbits | NPILOCKED, VINTEGER);
3246 		}
3247 		return;
3248 	}
3249 
3250 	if (namesamen(pp, x_("locked-primitives"), l) == 0 && l >= 1)
3251 	{
3252 		if (np != NONODEPROTO)
3253 		{
3254 			us_abortcommand(_("Primitive lock must be done for all prototypes (*)"));
3255 			return;
3256 		}
3257 		if (negated)
3258 		{
3259 			if ((us_useroptions&NOPRIMCHANGES) == 0)
3260 				ttyputverbose(M_("Locked primitives are already able to be freely altered")); else
3261 					ttyputverbose(M_("Locked primitives may now be freely edited"));
3262 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3263 				us_useroptions & ~NOPRIMCHANGES, VINTEGER);
3264 		} else
3265 		{
3266 			if ((us_useroptions&NOPRIMCHANGES) != 0)
3267 				ttyputverbose(M_("Locked primitive changes are already being disallowed")); else
3268 					ttyputverbose(M_("Locked primitive changes will not be allowed"));
3269 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3270 				us_useroptions | NOPRIMCHANGES, VINTEGER);
3271 		}
3272 		return;
3273 	}
3274 
3275 	if (namesamen(pp, x_("expanded"), l) == 0 && l >= 1)
3276 	{
3277 		if (np == NONODEPROTO)
3278 		{
3279 			for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3280 			{
3281 				if (!negated) (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3282 					np->userbits | WANTNEXPAND, VINTEGER); else
3283 						(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3284 							np->userbits & ~WANTNEXPAND, VINTEGER);
3285 			}
3286 		} else
3287 		{
3288 			if (np->primindex != 0)
3289 			{
3290 				if (!negated) us_abortcommand(_("Primitives are expanded by definition")); else
3291 					us_abortcommand(_("Cannot un-expand primitives"));
3292 				return;
3293 			}
3294 			if (!negated) (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3295 				np->userbits | WANTNEXPAND, VINTEGER); else
3296 					(void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3297 						np->userbits & ~WANTNEXPAND, VINTEGER);
3298 		}
3299 		ttyputverbose(M_("%s node prototypes will be %sexpanded on creation"), nname, (negated ? _("un-") : x_("")));
3300 		return;
3301 	}
3302 
3303 	if (namesamen(pp, x_("size"), l) == 0 && l >= 1)
3304 	{
3305 		if (np == NONODEPROTO)
3306 		{
3307 			us_abortcommand(_("Must change size on a single node"));
3308 			return;
3309 		}
3310 		if (np->primindex == 0)
3311 		{
3312 			us_abortcommand(_("Can only change default size on primitives"));
3313 			return;
3314 		}
3315 		if (count <= 2)
3316 		{
3317 			count = ttygetparam(_("X size: "), &us_defnodexsp, MAXPARS-2, &par[2]) + 2;
3318 			if (count == 2)
3319 			{
3320 				us_abortedmsg();
3321 				return;
3322 			}
3323 		}
3324 		pp = par[2];
3325 		i = atola(pp, 0);
3326 		if (i&1) i++;
3327 		if (count <= 3)
3328 		{
3329 			count = ttygetparam(_("Y size: "), &us_defnodeysp, MAXPARS-3, &par[3]) + 3;
3330 			if (count == 3)
3331 			{
3332 				us_abortedmsg();
3333 				return;
3334 			}
3335 		}
3336 		pp = par[3];
3337 		j = atola(pp, 0);
3338 		if (j&1) j++;
3339 		if (i < 0 || j < 0)
3340 		{
3341 			us_abortcommand(_("Sizes must not be negative"));
3342 			return;
3343 		}
3344 		nodeprotosizeoffset(np, &plx, &ply, &phx, &phy, NONODEPROTO);
3345 		nodesize[0] = i+plx+phx;
3346 		nodesize[1] = j+ply+phy;
3347 		nodesize[0] = nodesize[0] * WHOLE / el_curlib->lambda[np->tech->techindex];
3348 		nodesize[1] = nodesize[1] * WHOLE / el_curlib->lambda[np->tech->techindex];
3349 		(void)setvalkey((INTBIG)np, VNODEPROTO, el_node_size_default_key,
3350 			(INTBIG)nodesize, VINTEGER|VISARRAY|(2<<VLENGTHSH));
3351 		ttyputverbose(M_("%s nodes will be created %sx%s in size"), describenodeproto(np),
3352 			latoa(i, 0), latoa(j, 0));
3353 		return;
3354 	}
3355 
3356 	if (namesamen(pp, x_("placement"), l) == 0 && l >= 1)
3357 	{
3358 		if (np != NONODEPROTO)
3359 		{
3360 			/* get placement angle for this node */
3361 			var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle_key);
3362 			if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
3363 
3364 			if (count > 2)
3365 			{
3366 				pangle = (atofr(par[2])*10/WHOLE) % 3600;
3367 				if (pangle < 0) pangle += 3600;
3368 				if (namesame(&par[2][estrlen(par[2])-1], x_("t")) == 0) pangle += 3600;
3369 			} else if (pangle >= 6300) pangle = 0; else
3370 				pangle += 900;
3371 			(void)setvalkey((INTBIG)np, VNODEPROTO, us_placement_angle_key, pangle, VINTEGER);
3372 		} else
3373 		{
3374 			/* get placement angle for all nodes */
3375 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_placement_angle_key);
3376 			if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
3377 
3378 			if (count > 2)
3379 			{
3380 				pangle = (atofr(par[2])*10/WHOLE) % 3600;
3381 				if (pangle < 0) pangle += 3600;
3382 				if (namesame(&par[2][estrlen(par[2])-1], x_("t")) == 0) pangle += 3600;
3383 			} else if (pangle >= 6300) pangle = 0; else
3384 				pangle += 900;
3385 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_placement_angle_key, pangle, VINTEGER);
3386 		}
3387 		return;
3388 	}
3389 
3390 	ttyputbadusage(x_("defnode"));
3391 }
3392 
us_duplicate(INTBIG count,CHAR * par[])3393 void us_duplicate(INTBIG count, CHAR *par[])
3394 {
3395 	REGISTER NODEPROTO *np;
3396 	REGISTER GEOM **list;
3397 	REGISTER BOOLEAN interactiveplace;
3398 
3399 	/* get object */
3400 	np = us_needcell();
3401 	if (np == NONODEPROTO) return;
3402 	list = us_gethighlighted(WANTNODEINST | WANTARCINST, 0, 0);
3403 	if (list[0] == NOGEOM)
3404 	{
3405 		us_abortcommand(_("First select objects to duplicate"));
3406 		return;
3407 	}
3408 
3409 	if ((us_useroptions&NOMOVEAFTERDUP) != 0) interactiveplace = FALSE; else
3410 		interactiveplace = TRUE;
3411 	us_copylisttocell(list, np, np, TRUE, interactiveplace, TRUE);
3412 }
3413 
3414 #if 0		/* test code for John Wood */
3415 
3416 #define NUMTRANSISTOR 5
3417 #define DEFTRANSISTORWIDTH 3
3418 #define TRANSISTORWIDTH 30
3419 #define CELLNAME x_("multifingertransistor{lay}")
3420 
3421 void us_debugjohn(void)
3422 {
3423 	NODEPROTO *cell, *tra, *contact;
3424 	NODEINST *transni, *contactni, *lastcontactni;
3425 	PORTPROTO *topport, *botport, *conport;
3426 	ARCPROTO *active;
3427 	ARCINST *ai;
3428 	CHAR *par[2];
3429 	INTBIG lx, hx, ly, hy, sizex, sizey, sep, lambda, sizeycontact, bits,
3430 		tpx, tpy, cpx, cpy, wid, i;
3431 
3432 	lambda = el_curlib->lambda[el_curtech->techindex];
3433 	cell = newnodeproto(CELLNAME, el_curlib);
3434 	if (cell == NONODEPROTO) return;
3435 
3436 	/* get the objects we need */
3437 	tra = getnodeproto(x_("mocmos:N-Transistor"));
3438 	if (tra == NONODEPROTO) return;
3439 	contact = getnodeproto(x_("mocmos:Metal-1-N-Active-Con"));
3440 	conport = contact->firstportproto;
3441 	topport = getportproto(tra, x_("n-trans-diff-top"));
3442 	botport = getportproto(tra, x_("n-trans-diff-bottom"));
3443 	active = getarcproto(x_("mocmos:N-Active"));
3444 
3445 	/* get information for layout */
3446 	sizex = tra->highx - tra->lowx;
3447 	sizey = tra->highy - tra->lowy;
3448 	sizeycontact = contact->highy - contact->lowy;
3449 	sep = sizey * 2 - 32 * lambda;
3450 	bits = us_makearcuserbits(active);
3451 	wid = active->nominalwidth;
3452 
3453 	/* lay down the transistors */
3454 	for(i=0; i<NUMTRANSISTOR; i++)
3455 	{
3456 		lx = 0;   hx = sizex + (TRANSISTORWIDTH - DEFTRANSISTORWIDTH) * lambda;
3457 		ly = i*sep;   hy = ly + sizey;
3458 		transni = newnodeinst(tra, lx, hx, ly, hy, 0, 0, cell);
3459 		endobjectchange((INTBIG)transni, VNODEINST);
3460 		if (i < NUMTRANSISTOR-1)
3461 		{
3462 			ly = hy - lambda * 29 / 2;   hy = ly + sizeycontact;
3463 			contactni = newnodeinst(contact, lx, hx, ly, hy, 0, 0, cell);
3464 			endobjectchange((INTBIG)contactni, VNODEINST);
3465 
3466 			/* wire to the transistor */
3467 			portposition(transni, topport, &tpx, &tpy);
3468 			portposition(contactni, conport, &cpx, &cpy);
3469 			ai = newarcinst(active, wid, bits, transni, topport, tpx, tpy,
3470 				contactni, conport, cpx, cpy, cell);
3471 			endobjectchange((INTBIG)ai, VARCINST);
3472 		}
3473 		if (i > 0)
3474 		{
3475 			portposition(transni, botport, &tpx, &tpy);
3476 			portposition(lastcontactni, conport, &cpx, &cpy);
3477 			ai = newarcinst(active, wid, bits, transni, botport, tpx, tpy,
3478 				lastcontactni, conport, cpx, cpy, cell);
3479 			endobjectchange((INTBIG)ai, VARCINST);
3480 		}
3481 		lastcontactni = contactni;
3482 	}
3483 
3484 	/* display the result */
3485 	par[0] = CELLNAME;
3486 	us_editcell(1, par);
3487 }
3488 #endif
3489