1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrcomrs.c
6  * User interface tool: command handler for R through S
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 "usr.h"
35 #include "usrtrack.h"
36 #include "efunction.h"
37 #include "conlay.h"
38 #include "tecgen.h"
39 #include "usrdiacom.h"
40 
us_redraw(INTBIG count,CHAR * par[])41 void us_redraw(INTBIG count, CHAR *par[])
42 {
43 	Q_UNUSED( count );
44 	Q_UNUSED( par );
45 
46 	/* save highlighting */
47 	us_pushhighlight();
48 	us_clearhighlightcount();
49 
50 	/* re-draw the status display */
51 	us_redostatus(NOWINDOWFRAME);
52 
53 	/* redraw the color screen */
54 	us_drawmenu(0, NOWINDOWFRAME);
55 
56 	/* restore highlighting */
57 	us_pophighlight(FALSE);
58 
59 	/* flush queued display */
60 	us_endchanges(NOWINDOWPART);
61 }
62 
us_remember(INTBIG count,CHAR * par[])63 void us_remember(INTBIG count, CHAR *par[])
64 {
65 	REGISTER INTBIG i, newtotal;
66 	REGISTER CHAR **newpar;
67 	REGISTER USERCOM *uc;
68 
69 	if (count > us_lastcommandtotal)
70 	{
71 		newtotal = us_lastcommandtotal * 2;
72 		if (count > us_lastcommandtotal) newtotal = count + 4;
73 		newpar = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), us_tool->cluster);
74 		if (newpar == 0) return;
75 		for(i=0; i<us_lastcommandtotal; i++)
76 			newpar[i] = us_lastcommandpar[i];
77 		for(i=us_lastcommandtotal; i<newtotal; i++) newpar[i] = 0;
78 		if (us_lastcommandtotal > 0) efree((CHAR *)us_lastcommandpar);
79 		us_lastcommandpar = newpar;
80 		us_lastcommandtotal = newtotal;
81 	}
82 	for(i=0; i<count; i++)
83 	{
84 		if (us_lastcommandpar[i] != 0)
85 			efree((CHAR *)us_lastcommandpar[i]);
86 		(void)allocstring(&us_lastcommandpar[i], par[i], us_tool->cluster);
87 	}
88 	us_lastcommandcount = count;
89 
90 	/* and execute the command, too */
91 	uc = us_buildcommand(count, par);
92 	if (uc == NOUSERCOM) return;
93 	us_executesafe(uc, FALSE, FALSE, FALSE);
94 	us_freeusercom(uc);
95 }
96 
us_rename(INTBIG count,CHAR * par[])97 void us_rename(INTBIG count, CHAR *par[])
98 {
99 	CHAR prompt[80], newfile[100],*newpar[10], *oldname, si[10], sj[10];
100 	REGISTER INTBIG k, len, i, savei, command, savecommand, variable, savevariable,
101 		varnewkey, varoldkey;
102 	REGISTER CHAR *ch, *pt, *netname, *savenetname, **newlist, *str, *which;
103 	REGISTER NODEPROTO *np, *lnt, *savenp, *curcell;
104 	REGISTER NODEINST *ni;
105 	REGISTER PORTPROTO *pp, *savepp;
106 	REGISTER LIBRARY *lib, *olib, *savelib;
107 	REGISTER TECHNOLOGY *tech, *otech, *savetech;
108 	REGISTER ARCPROTO *ap, *oat, *saveap;
109 	REGISTER VARIABLE *macvar, *savemacvar, *var;
110 	REGISTER POPUPMENU *opm;
111 	POPUPMENU *pm, *savepm;
112 	REGISTER NETWORK *net;
113 	REGISTER USERCOM *item;
114 	COMMANDBINDING commandbinding;
115 	REGISTER void *infstr;
116 
117 	/* get the former name */
118 	if (count < 2)
119 	{
120 		ttyputusage(x_("rename OLDNAME NEWNAME [TYPE]"));
121 		return;
122 	}
123 	pt = par[0];
124 	curcell = getcurcell();
125 
126 	/* see if any nodeprotos have that name */
127 	np = getnodeproto(pt);
128 
129 	/* see if any arcprotos have that name */
130 	ap = getarcproto(pt);
131 
132 	/* see if any libraries have that name */
133 	lib = getlibrary(pt);
134 
135 	/* see if any ports in this cell have that name */
136 	if (curcell == NONODEPROTO) pp = NOPORTPROTO; else
137 		pp = getportproto(curcell, pt);
138 
139 	/* see if any macros have that name */
140 	macvar = us_getmacro(pt);
141 
142 	/* see if any technologies have that name (search by hand because "gettechnology" handles partial matches) */
143 	for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
144 		if (namesame(pt, tech->techname) == 0) break;
145 
146 	/* see if any user commands have that name */
147 	for(i=0; us_lcommand[i].name != 0; i++)
148 		if (namesame(us_lcommand[i].name, pt) == 0) break;
149 	if (us_lcommand[i].name == 0) command = -1; else command = i;
150 
151 	/* see if any database variables have that name */
152 	for(i=0; i<el_numnames; i++)
153 		if (namesame(el_namespace[i], pt) == 0) break;
154 	if (i >= el_numnames) variable = -1; else variable = i;
155 
156 	/* see if any popup menus have that name */
157 	for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
158 		if (namesame(pm->name, pt) == 0) break;
159 
160 	/* see if any networks have that name */
161 	netname = 0;
162 	net = NONETWORK;
163 	if (curcell != NONODEPROTO)
164 	{
165 		len = estrlen(pt);
166 		for(net = curcell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
167 		{
168 			for(k=0; k<net->namecount; k++)
169 			{
170 				ch = networkname(net, k);
171 				if (namesamen(ch, pt, len) == 0 && (ch[len] == '[' || ch[len] == 0))
172 				{
173 					netname = pt;
174 					break;
175 				}
176 			}
177 			if (netname != 0) break;
178 		}
179 	}
180 
181 	/* special case: if port and network are possible, exclude the network */
182 	if (pp != NOPORTPROTO && netname != 0) netname = 0;
183 
184 	/* see how many different things have that name */
185 	i = 0;
186 	if (np != NONODEPROTO) i++;
187 	if (ap != NOARCPROTO) i++;
188 	if (lib != NOLIBRARY) i++;
189 	if (pp != NOPORTPROTO) i++;
190 	if (macvar != NOVARIABLE) i++;
191 	if (tech != NOTECHNOLOGY) i++;
192 	if (command >= 0) i++;
193 	if (variable >= 0) i++;
194 	if (pm != NOPOPUPMENU) i++;
195 	if (netname != 0) i++;
196 
197 	/* quit if the name doesn't exist */
198 	if (i == 0)
199 	{
200 		us_abortcommand(_("Nothing named %s"), pt);
201 		return;
202 	}
203 
204 	/* if name matches more than one type, exclude matches that are not exact */
205 	if (i != 1)
206 	{
207 		savenp = np;
208 		saveap = ap;
209 		savelib = lib;
210 		savepp = pp;
211 		savemacvar = macvar;
212 		savetech = tech;
213 		savecommand = command;
214 		savevariable = variable;
215 		savepm = pm;
216 		savenetname = netname;
217 		savei = i;
218 
219 		if (np != NONODEPROTO && namesame(np->protoname, pt) != 0)
220 		{
221 			np = NONODEPROTO;   i--;
222 		}
223 		if (ap != NOARCPROTO && namesame(ap->protoname, pt) != 0)
224 		{
225 			ap = NOARCPROTO;   i--;
226 		}
227 		if (lib != NOLIBRARY && namesame(lib->libname, pt) != 0)
228 		{
229 			lib = NOLIBRARY;   i--;
230 		}
231 		if (pp != NOPORTPROTO && namesame(pp->protoname, pt) != 0)
232 		{
233 			pp = NOPORTPROTO;   i--;
234 		}
235 		if (macvar != NOVARIABLE && namesame(&makename(macvar->key)[11], pt) != 0)
236 		{
237 			macvar = NOVARIABLE;   i--;
238 		}
239 		if (tech != NOTECHNOLOGY && namesame(tech->techname, pt) != 0)
240 		{
241 			tech = NOTECHNOLOGY;   i--;
242 		}
243 		if (command >= 0 && namesame(us_lcommand[command].name, pt) != 0)
244 		{
245 			command = -1;   i--;
246 		}
247 		if (variable >= 0 && namesame(el_namespace[variable], pt) != 0)
248 		{
249 			variable = -1;   i--;
250 		}
251 		if (pm != NOPOPUPMENU && namesame(pm->name, pt) != 0)
252 		{
253 			pm = NOPOPUPMENU;   i--;
254 		}
255 		if (netname != 0 && namesame(netname, pt) != 0)
256 		{
257 			netname = 0;   i--;
258 		}
259 
260 		if (i <= 0)
261 		{
262 			np = savenp;
263 			ap = saveap;
264 			lib = savelib;
265 			pp = savepp;
266 			macvar = savemacvar;
267 			tech = savetech;
268 			command = savecommand;
269 			variable = savevariable;
270 			pm = savepm;
271 			netname = savenetname;
272 			i = savei;
273 		}
274 	}
275 
276 	/* build the ambiguity string */
277 	(void)estrcpy(prompt, M_("Rename the"));
278 	i = 0;
279 	if (np != NONODEPROTO)
280 	{
281 		(void)estrcat(prompt, M_(" nodeProto")); i++;
282 	}
283 	if (ap != NOARCPROTO)
284 	{
285 		if (i) (void)estrcat(prompt, M_(" or"));
286 		(void)estrcat(prompt, M_(" Arc")); i++;
287 	}
288 	if (lib != NOLIBRARY)
289 	{
290 		if (i) (void)estrcat(prompt, M_(" or"));
291 		(void)estrcat(prompt, M_(" Library")); i++;
292 	}
293 	if (pp != NOPORTPROTO)
294 	{
295 		if (i) (void)estrcat(prompt, M_(" or"));
296 		(void)estrcat(prompt, M_(" poRt")); i++;
297 	}
298 	if (macvar != NOVARIABLE)
299 	{
300 		if (i) (void)estrcat(prompt, M_(" or"));
301 		(void)estrcat(prompt, M_(" Macro")); i++;
302 	}
303 	if (tech != NOTECHNOLOGY)
304 	{
305 		if (i) (void)estrcat(prompt, M_(" or"));
306 		(void)estrcat(prompt, M_(" Technology")); i++;
307 	}
308 	if (command >= 0)
309 	{
310 		if (i) (void)estrcat(prompt, M_(" or"));
311 		(void)estrcat(prompt, M_(" commanD")); i++;
312 	}
313 	if (variable >= 0)
314 	{
315 		if (i) (void)estrcat(prompt, M_(" or"));
316 		(void)estrcat(prompt, M_(" Variable")); i++;
317 	}
318 	if (pm != NOPOPUPMENU)
319 	{
320 		if (i) (void)estrcat(prompt, M_(" or"));
321 		(void)estrcat(prompt, M_(" pop-Up-menu")); i++;
322 	}
323 	if (netname != 0)
324 	{
325 		if (i) (void)estrcat(prompt, M_(" or"));
326 		(void)estrcat(prompt, M_(" Network")); i++;
327 	}
328 	(void)estrcat(prompt, x_(": "));
329 
330 	/* if name is more than one type of object, ask which */
331 	while (i != 1)
332 	{
333 		if (count >= 3)
334 		{
335 			which = par[2];
336 			count = 2;
337 		} else
338 		{
339 			which = ttygetline(prompt);
340 			if (which == 0) return;
341 		}
342 		switch (*which)
343 		{
344 			case 'p':   case 'P':
345 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
346 				macvar=NOVARIABLE; tech=NOTECHNOLOGY; command = -1;
347 				variable = -1;     pm = NOPOPUPMENU;
348 				netname = 0;       i=1;               break;
349 			case 'a':   case 'A':
350 				np=NONODEPROTO;    lib=NOLIBRARY;     pp=NOPORTPROTO;
351 				macvar=NOVARIABLE; tech=NOTECHNOLOGY; command = -1;
352 				variable = -1;     pm = NOPOPUPMENU;
353 				netname = 0;       i=1;               break;
354 			case 'l':   case 'L':
355 				ap=NOARCPROTO;     np=NONODEPROTO;    pp=NOPORTPROTO;
356 				macvar=NOVARIABLE; tech=NOTECHNOLOGY; command = -1;
357 				variable = -1;     pm = NOPOPUPMENU;
358 				netname = 0;       i=1;               break;
359 			case 'r':   case 'R':
360 				ap=NOARCPROTO;     lib=NOLIBRARY;     np=NONODEPROTO;
361 				macvar=NOVARIABLE; tech=NOTECHNOLOGY; command = -1;
362 				variable = -1;     pm = NOPOPUPMENU;
363 				netname = 0;       i=1;               break;
364 			case 'm':   case 'M':
365 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
366 				np=NONODEPROTO;    tech=NOTECHNOLOGY; command = -1;
367 				variable = -1;     pm = NOPOPUPMENU;
368 				netname = 0;       i=1;               break;
369 			case 't':   case 'T':
370 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
371 				np=NONODEPROTO;    macvar=NOVARIABLE; command = -1;
372 				variable = -1;     pm = NOPOPUPMENU;
373 				netname = 0;       i=1;               break;
374 			case 'd':   case 'D':
375 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
376 				np=NONODEPROTO;    tech=NOTECHNOLOGY; macvar=NOVARIABLE;
377 				variable = -1;     pm = NOPOPUPMENU;
378 				netname = 0;       i=1;               break;
379 			case 'v':   case 'V':
380 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
381 				np=NONODEPROTO;    tech=NOTECHNOLOGY; macvar=NOVARIABLE;
382 				command = -1;      pm = NOPOPUPMENU;
383 				netname = 0;       i=1;               break;
384 			case 'u':   case 'U':
385 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
386 				np=NONODEPROTO;    tech=NOTECHNOLOGY; macvar=NOVARIABLE;
387 				variable = -1;     command = -1;
388 				netname = 0;       i=1;               break;
389 			case 'n':   case 'N':
390 				ap=NOARCPROTO;     lib=NOLIBRARY;     pp=NOPORTPROTO;
391 				np=NONODEPROTO;    tech=NOTECHNOLOGY; macvar=NOVARIABLE;
392 				variable = -1;     command = -1;
393 				pm=NOPOPUPMENU;    i=1;               break;
394 			case 0:   us_abortedmsg();  return;
395 		}
396 	}
397 
398 	/* get new name */
399 	pt = par[1];
400 
401 	/* handle nodeproto name change */
402 	if (np != NONODEPROTO)
403 	{
404 		/* be sure the name is legal */
405 		if (!us_validname(pt, VNODEPROTO)) return;
406 
407 		/* check for duplicate name */
408 		if (estrcmp(np->protoname, pt) == 0)
409 		{
410 			ttyputmsg(_("Nodeproto name has not changed"));
411 			return;
412 		}
413 		if (np->primindex != 0)
414 		{
415 			/* check for duplicate primitive name */
416 			for(lnt = np->tech->firstnodeproto; lnt != NONODEPROTO; lnt = lnt->nextnodeproto)
417 				if (np != lnt && namesame(lnt->protoname, pt) == 0)
418 			{
419 				us_abortcommand(_("Already a primitive with that name"));
420 				return;
421 			}
422 		} else
423 		{
424 			/* check for duplicate cell name */
425 			for(lnt = np->lib->firstnodeproto; lnt != NONODEPROTO; lnt = lnt->nextnodeproto)
426 			{
427 				if (np == lnt) continue;
428 				if (np->cellview == lnt->cellview && estrcmp(lnt->protoname, pt) == 0)
429 				{
430 					us_abortcommand(_("Already a cell with that name"));
431 					return;
432 				}
433 			}
434 		}
435 
436 		/* change the node name */
437 		ttyputverbose(M_("Nodeproto %s renamed to %s"), np->protoname, pt);
438 		lnt = us_curnodeproto;
439 		if (lnt == np) us_setnodeproto(NONODEPROTO);
440 		(void)setval((INTBIG)np, VNODEPROTO, x_("protoname"), (INTBIG)pt, VSTRING);
441 		if (lnt == np) us_setnodeproto(np);
442 	}
443 
444 	/* handle arcproto name change */
445 	if (ap != NOARCPROTO)
446 	{
447 		/* be sure the name is legal */
448 		if (!us_validname(pt, VARCPROTO)) return;
449 
450 		/* check for duplicate name */
451 		if (estrcmp(ap->protoname, pt) == 0)
452 		{
453 			ttyputmsg(_("Arc name has not changed"));
454 			return;
455 		}
456 		for(oat = ap->tech->firstarcproto; oat != NOARCPROTO; oat = oat->nextarcproto)
457 			if (ap != oat && namesame(pt, oat->protoname) == 0)
458 		{
459 			us_abortcommand(_("Already an arc of that name"));
460 			return;
461 		}
462 
463 		/* change the arc name */
464 		(void)allocstring(&oldname, ap->protoname, el_tempcluster);
465 		ttyputverbose(M_("Arc prototype %s renamed to %s"), describearcproto(ap), pt);
466 		oat = us_curarcproto;
467 		if (oat == ap) us_setarcproto(NOARCPROTO, TRUE);
468 		(void)setval((INTBIG)ap, VARCPROTO, x_("protoname"), (INTBIG)pt, VSTRING);
469 		if (oat == ap) us_setarcproto(ap, TRUE);
470 
471 		/* change any component menu entries that mention this arc */
472 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
473 		if (var != NOVARIABLE)
474 		{
475 			for(i=0; i<us_menuy*us_menux; i++)
476 			{
477 				us_parsebinding(((CHAR **)var->addr)[i], &commandbinding);
478 				item = us_makecommand(commandbinding.command);
479 				if (namesame(item->comname, x_("getproto")) == 0)
480 				{
481 					if (item->count >= 2 && namesame(item->word[0], x_("arc")) == 0)
482 					{
483 						if (namesame(item->word[1], oldname) == 0)
484 						{
485 							/* rename this item */
486 							if (us_menupos <= 1)
487 							{
488 								(void)esnprintf(si, 10, x_("%ld"), i%us_menux);
489 								(void)esnprintf(sj, 10, x_("%ld"), i/us_menux);
490 							} else
491 							{
492 								(void)esnprintf(si, 10, x_("%ld"), i/us_menuy);
493 								(void)esnprintf(sj, 10, x_("%ld"), i%us_menuy);
494 							}
495 							newpar[0] = x_("set");          newpar[1] = x_("menu");
496 							newpar[2] = x_("background");   newpar[3] = _("red");
497 							newpar[4] = sj;             newpar[5] = si;
498 							newpar[6] = x_("getproto");     newpar[7] = x_("arc");
499 							newpar[8] = describearcproto(ap);
500 							us_bind(9, newpar);
501 						}
502 					}
503 				}
504 				us_freeusercom(item);
505 				us_freebindingparse(&commandbinding);
506 			}
507 		}
508 		efree(oldname);
509 	}
510 
511 	/* handle library name change */
512 	if (lib != NOLIBRARY)
513 	{
514 		/* get pure library name if path was given */
515 		ch = skippath(pt);
516 
517 		/* be sure the name is legal */
518 		if (!us_validname(ch, VLIBRARY)) return;
519 
520 		/* remove any ".elib" extension */
521 		k = 0;
522 		for(str = ch; *str != 0; str++)
523 			if (namesame(str, x_(".elib")) == 0)
524 		{
525 			k = 1;
526 			*str = 0;
527 			break;
528 		}
529 
530 		/* check for duplicate name */
531 		if (estrcmp(lib->libname, ch) == 0 && ch == pt)
532 		{
533 			ttyputverbose(M_("Library name has not changed"));
534 			return;
535 		}
536 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
537 			if (olib != lib && namesame(olib->libname, ch) == 0)
538 		{
539 			us_abortcommand(_("Already a library of that name"));
540 			return;
541 		}
542 
543 		/* change the library name */
544 		ttyputmsg(_("Library %s renamed to %s"), lib->libname, ch);
545 		(void)setval((INTBIG)lib, VLIBRARY, x_("libname"), (INTBIG)ch, VSTRING);
546 
547 		/* change the library file name too */
548 		if (k != 0) *str = '.';
549 		if (ch == pt)
550 		{
551 			/* no path given: use old path */
552 			(void)estrcpy(newfile, lib->libfile);
553 			ch = skippath(newfile);
554 			(void)estrcpy(ch, pt);
555 			pt = newfile;
556 		}
557 		(void)setval((INTBIG)lib, VLIBRARY, x_("libfile"), (INTBIG)pt, VSTRING);
558 
559 		/* mark for saving, all libraries that depend on this */
560 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
561 		{
562 			if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
563 			if (olib == lib) continue;
564 
565 			/* see if any cells in this library reference the renamed one */
566 			for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
567 			{
568 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
569 				{
570 					if (ni->proto->primindex != 0) continue;
571 					if (ni->proto->lib == lib) break;
572 				}
573 				if (ni != NONODEINST) break;
574 			}
575 			if (np != NONODEPROTO) olib->userbits |= LIBCHANGEDMAJOR;
576 		}
577 	}
578 
579 	/* handle port name change */
580 	if (pp != NOPORTPROTO)
581 	{
582 		/* be sure the name is legal */
583 		if (!us_validname(pt, VPORTPROTO)) return;
584 
585 		/* rename the port */
586 		us_renameport(pp, pt);
587 	}
588 
589 	/* handle macro change */
590 	if (macvar != NOVARIABLE)
591 	{
592 		/* be sure the name is legal */
593 		if (!us_validname(pt, VSTRING)) return;
594 
595 		/* check for duplicate name */
596 		if (namesame(&makename(macvar->key)[11], pt) == 0)
597 		{
598 			ttyputmsg(_("Macro name has not changed"));
599 			return;
600 		}
601 		var = us_getmacro(pt);
602 		if (var != macvar)
603 		{
604 			us_abortcommand(_("Already a macro of that name"));
605 			return;
606 		}
607 
608 		/* make sure macro name isn't overloading existing command or popup */
609 		for(i=0; us_lcommand[i].name != 0; i++)
610 			if (namesame(pt, us_lcommand[i].name) == 0)
611 		{
612 			us_abortcommand(_("There is a command with that name"));
613 			return;
614 		}
615 		for(opm=us_firstpopupmenu; opm!=NOPOPUPMENU; opm=opm->nextpopupmenu)
616 			if (namesame(pt, opm->name) == 0)
617 		{
618 			us_abortcommand(_("There is a popup menu with that name"));
619 			return;
620 		}
621 
622 		/* save the macro data */
623 		len = getlength(macvar);
624 		newlist = (CHAR **)emalloc(len * (sizeof (CHAR *)), el_tempcluster);
625 		if (newlist == 0) return;
626 		for(i=0; i<len; i++)
627 			(void)allocstring(&newlist[i], ((CHAR **)var->addr)[i], el_tempcluster);
628 
629 		/* change the macro name */
630 		ttyputverbose(M_("Macro %s renamed to %s"), &makename(macvar->key)[11], pt);
631 		(void)delvalkey((INTBIG)us_tool, VTOOL, (INTBIG)macvar->key);
632 		infstr = initinfstr();
633 		addstringtoinfstr(infstr, x_("USER_macro_"));
634 		addstringtoinfstr(infstr, pt);
635 		(void)setval((INTBIG)us_tool, VTOOL, returninfstr(infstr), (INTBIG)newlist,
636 			VSTRING|VISARRAY|(len<<VLENGTHSH)|VDONTSAVE);
637 		for(i=0; i<len; i++) efree(newlist[i]);
638 		efree((CHAR *)newlist);
639 	}
640 
641 	/* handle technology change */
642 	if (tech != NOTECHNOLOGY)
643 	{
644 		/* be sure the name is legal */
645 		if (!us_validname(pt, VTECHNOLOGY)) return;
646 
647 		/* check for duplicate name */
648 		if (estrcmp(tech->techname, pt) == 0)
649 		{
650 			ttyputmsg(_("Technology name has not changed"));
651 			return;
652 		}
653 		for(otech = el_technologies; otech != NOTECHNOLOGY; otech = otech->nexttechnology)
654 			if (otech != tech && namesame(otech->techname, pt) == 0)
655 		{
656 			us_abortcommand(_("Already a technology of that name"));
657 			return;
658 		}
659 
660 		/* change the technology name */
661 		ttyputmsg(_("Technology %s renamed to %s"), tech->techname, pt);
662 		(void)setval((INTBIG)tech, VTECHNOLOGY, x_("techname"), (INTBIG)pt, VSTRING);
663 	}
664 
665 	/* handle user command change */
666 	if (command >= 0)
667 	{
668 		/* be sure the name is legal */
669 		if (!us_validname(pt, VSTRING)) return;
670 
671 		/* check for duplicate name */
672 		if (estrcmp(us_lcommand[command].name, pt) == 0)
673 		{
674 			ttyputmsg(_("Command name has not changed"));
675 			return;
676 		}
677 		for(i=0; us_lcommand[i].name != 0; i++)
678 			if (i != command && namesame(pt, us_lcommand[i].name) == 0)
679 		{
680 			us_abortcommand(_("Already a command of that name"));
681 			return;
682 		}
683 
684 		/* make sure command name isn't overloading existing macro or popup */
685 		if (us_getmacro(pt) != NOVARIABLE)
686 		{
687 			us_abortcommand(_("There is a macro with that name"));
688 			return;
689 		}
690 		for(opm=us_firstpopupmenu; opm!=NOPOPUPMENU; opm=opm->nextpopupmenu)
691 			if (namesame(pt, opm->name) == 0)
692 		{
693 			us_abortcommand(_("There is a popup menu with that name"));
694 			return;
695 		}
696 
697 		/*
698 		 * change the command name
699 		 * Note: this allocates space that is never freed !!!
700 		 */
701 		ttyputverbose(M_("Command %s renamed to %s"), us_lcommand[command].name, pt);
702 		if (allocstring(&us_lcommand[command].name, pt, us_tool->cluster))
703 			ttyputnomemory();
704 	}
705 
706 	/* handle variable change */
707 	if (variable >= 0)
708 	{
709 		/* be sure the name is legal */
710 		if (!us_validname(pt, VSTRING)) return;
711 
712 		/* check for duplicate name */
713 		if (namesame(el_namespace[variable], pt) == 0)
714 		{
715 			ttyputmsg(_("Variable name has not changed"));
716 			return;
717 		}
718 		for(i=0; i<el_numnames; i++)
719 			if (namesame(pt, el_namespace[i]) == 0)
720 		{
721 			us_abortcommand(_("Already a variable of that name"));
722 			return;
723 		}
724 
725 		/* change the variable name */
726 		ttyputverbose(M_("Variable %s renamed to %s"), el_namespace[variable], pt);
727 		renameval(el_namespace[variable], pt);
728 	}
729 
730 	/* handle popup menu change */
731 	if (pm != NOPOPUPMENU)
732 	{
733 		/* be sure the name is legal */
734 		if (!us_validname(pt, VSTRING)) return;
735 
736 		/* check for duplicate name */
737 		if (namesame(pm->name, pt) == 0)
738 		{
739 			ttyputmsg(_("Popup menu name has not changed"));
740 			return;
741 		}
742 		for(opm=us_firstpopupmenu; opm!=NOPOPUPMENU; opm=opm->nextpopupmenu)
743 			if (namesame(pt, opm->name) == 0)
744 		{
745 			us_abortcommand(_("Already a popup menu with that name"));
746 			return;
747 		}
748 
749 		/* make sure popup name isn't overloading existing command or menu */
750 		for(i=0; us_lcommand[i].name != 0; i++)
751 			if (namesame(pt, us_lcommand[i].name) == 0)
752 		{
753 			us_abortcommand(_("There is a command with that name"));
754 			return;
755 		}
756 		if (us_getmacro(pt) != NOVARIABLE)
757 		{
758 			us_abortcommand(_("There is a macro with that name"));
759 			return;
760 		}
761 
762 		/* change the popup name */
763 		ttyputverbose(M_("Popup menu %s renamed to %s"), pm->name, pt);
764 
765 		/* find the old popup menu */
766 		infstr = initinfstr();
767 		addstringtoinfstr(infstr, x_("USER_binding_popup_"));
768 		addstringtoinfstr(infstr, pm->name);
769 		varoldkey = makekey(returninfstr(infstr));
770 		var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, varoldkey);
771 		if (var == NOVARIABLE)
772 		{
773 			us_abortcommand(_("Cannot find popup menu %s"), pm->name);
774 			return;
775 		}
776 		len = getlength(var);
777 
778 		/* create the new popup menu with the new name and old data */
779 		infstr = initinfstr();
780 		addstringtoinfstr(infstr, x_("USER_binding_popup_"));
781 		addstringtoinfstr(infstr, pt);
782 		varnewkey = makekey(returninfstr(infstr));
783 		(void)setvalkey((INTBIG)us_tool, VTOOL, varnewkey, (INTBIG)var->addr,
784 			VSTRING|VISARRAY|VDONTSAVE|(len<<VLENGTHSH));
785 
786 		/* now delete the former popup menu */
787 		(void)delvalkey((INTBIG)us_tool, VTOOL, varoldkey);
788 	}
789 
790 	/* handle network name change */
791 	if (netname != 0)
792 	{
793 		/* be sure the name is legal */
794 		if (!us_validname(pt, VNETWORK)) return;
795 
796 		(void)asktool(net_tool, x_("rename"), (INTBIG)netname, (INTBIG)pt, (INTBIG)net->parent);
797 		return;
798 	}
799 }
800 
us_replace(INTBIG count,CHAR * par[])801 void us_replace(INTBIG count, CHAR *par[])
802 {
803 	REGISTER INTBIG i, total, len;
804 	REGISTER BOOLEAN universal, ignoreportnames, allowmissingports, connected,
805 		nodeswitharcs, thiscell, thislibrary;
806 	REGISTER CHAR *pt;
807 	REGISTER NODEPROTO *np, *oldntype, *cell, *curcell;
808 	REGISTER ARCPROTO *ap, *oldatype;
809 	REGISTER NODEINST *ni, *newno, *lni, *onlynewno, *rni;
810 	REGISTER ARCINST *ai, *newar, *lai, *onlynewar, *rai;
811 	REGISTER PORTARCINST *pi, *opi;
812 	HIGHLIGHT newhigh;
813 	REGISTER GEOM **list, *firstgeom, *geom;
814 	REGISTER LIBRARY *lib;
815 	REGISTER void *infstr;
816 	extern COMCOMP us_replacep;
817 
818 	/* find highlighted object to be replaced */
819 	list = us_gethighlighted(WANTNODEINST|WANTARCINST, 0, 0);
820 	firstgeom = list[0];
821 	if (firstgeom == NOGEOM) return;
822 	curcell = us_needcell();
823 	if (curcell == NONODEPROTO) return;
824 
825 	/* handle node replacement */
826 	if (firstgeom->entryisnode)
827 	{
828 		/* get node to be replaced */
829 		ni = firstgeom->entryaddr.ni;
830 
831 		/* disallow replacing if lock is on */
832 		if (us_cantedit(ni->parent, ni, TRUE)) return;
833 
834 		/* get nodeproto to replace it with */
835 		if (count == 0)
836 		{
837 			count = ttygetparam(M_("Node name: "), &us_replacep, MAXPARS, par);
838 			if (count == 0)
839 			{
840 				us_abortedmsg();
841 				return;
842 			}
843 		}
844 		np = getnodeproto(par[0]);
845 		if (np == NONODEPROTO)
846 		{
847 			us_abortcommand(_("Nothing called '%s'"), par[0]);
848 			return;
849 		}
850 
851 		/* sanity check */
852 		oldntype = ni->proto;
853 		if (oldntype == np)
854 		{
855 			us_abortcommand(_("Node already of type %s"), describenodeproto(np));
856 			return;
857 		}
858 
859 		/* get any arguments to the replace */
860 		ignoreportnames = allowmissingports = connected = thiscell = thislibrary = universal = FALSE;
861 		if (count > 1)
862 		{
863 			len = estrlen(pt = par[1]);
864 			if (namesamen(pt, x_("connected"), len) == 0) connected = TRUE;
865 			if (namesamen(pt, x_("this-cell"), len) == 0) thiscell = TRUE;
866 			if (namesamen(pt, x_("this-library"), len) == 0) thislibrary = TRUE;
867 			if (namesamen(pt, x_("universally"), len) == 0) universal = TRUE;
868 			if (namesamen(pt, x_("ignore-port-names"), len) == 0) ignoreportnames = TRUE;
869 			if (namesamen(pt, x_("allow-missing-ports"), len) == 0) allowmissingports = TRUE;
870 		}
871 
872 		/* clear highlighting */
873 		us_clearhighlightcount();
874 
875 		/* replace the nodeinsts */
876 		infstr = initinfstr();
877 		for(ni = curcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
878 			ni->temp1 = 0;
879 		for(i=0; list[i] != NOGEOM; i++)
880 		{
881 			geom = list[i];
882 			if (!geom->entryisnode) continue;
883 			ni = geom->entryaddr.ni;
884 			onlynewno = us_replacenodeinst(ni, np, ignoreportnames, allowmissingports);
885 			if (onlynewno == NONODEINST)
886 			{
887 				us_abortcommand(_("%s does not fit in the place of %s"), describenodeproto(np),
888 					describenodeproto(oldntype));
889 				newhigh.status = HIGHFROM;
890 				newhigh.cell = curcell;
891 				newhigh.fromgeom = ni->geom;
892 				newhigh.fromport = NOPORTPROTO;
893 				newhigh.frompoint = 0;
894 				newhigh.fromvar = NOVARIABLE;
895 				newhigh.fromvarnoeval = NOVARIABLE;
896 				us_addhighlight(&newhigh);
897 				(void)returninfstr(infstr);
898 				return;
899 			}
900 			onlynewno->temp1 = 1;
901 			formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
902 				describenodeproto(onlynewno->parent), (INTBIG)onlynewno->geom);
903 		}
904 
905 		/* do additional replacements if requested */
906 		total = 1;
907 		if (universal)
908 		{
909 			/* replace in all cells of library if "universally" used */
910 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
911 				for(cell = lib->firstnodeproto; cell != NONODEPROTO;
912 					cell = cell->nextnodeproto)
913 			{
914 				for(lni = cell->firstnodeinst; lni != NONODEINST; lni = lni->nextnodeinst)
915 				{
916 					if (lni->proto != oldntype) continue;
917 
918 					/* do not replace the example icon */
919 					if (isiconof(oldntype, cell))
920 					{
921 						ttyputmsg(_("Example icon in cell %s not replaced"), describenodeproto(cell));
922 						continue;
923 					}
924 
925 					/* disallow replacing if lock is on */
926 					if (us_cantedit(cell, lni, TRUE)) continue;
927 
928 					newno = us_replacenodeinst(lni, np, ignoreportnames, allowmissingports);
929 					if (newno != NONODEINST)
930 					{
931 						total++;
932 						formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
933 							describenodeproto(newno->parent), (INTBIG)newno->geom);
934 					}
935 					if (stopping(STOPREASONREPLACE)) break;
936 				}
937 			}
938 			ttyputmsg(_("All %ld %s nodes in all libraries replaced with %s"), total,
939 				describenodeproto(oldntype), describenodeproto(np));
940 		} else if (thislibrary)
941 		{
942 			/* replace throughout this library if "this-library" used */
943 			for(cell = el_curlib->firstnodeproto; cell != NONODEPROTO;
944 				cell = cell->nextnodeproto)
945 			{
946 				for(lni = cell->firstnodeinst; lni != NONODEINST; lni = lni->nextnodeinst)
947 					if (lni->proto == oldntype)
948 				{
949 					/* disallow replacing if lock is on */
950 					if (us_cantedit(cell, lni, TRUE)) continue;
951 
952 					newno = us_replacenodeinst(lni, np, ignoreportnames, allowmissingports);
953 					if (newno != NONODEINST)
954 					{
955 						total++;
956 						formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
957 							describenodeproto(newno->parent), (INTBIG)newno->geom);
958 					}
959 					if (stopping(STOPREASONREPLACE)) break;
960 				}
961 			}
962 			ttyputmsg(_("All %ld %s nodes in library %s replaced with %s"), total,
963 				describenodeproto(oldntype), el_curlib->libname, describenodeproto(np));
964 		} else if (thiscell)
965 		{
966 			/* replace throughout this cell if "this-cell" used */
967 			for(lni = curcell->firstnodeinst; lni != NONODEINST; lni = lni->nextnodeinst)
968 				if (lni->proto == oldntype)
969 			{
970 				/* disallow replacing if lock is on */
971 				if (us_cantedit(curcell, lni, TRUE)) continue;
972 
973 				newno = us_replacenodeinst(lni, np, ignoreportnames, allowmissingports);
974 				if (newno != NONODEINST)
975 				{
976 					total++;
977 					formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
978 						describenodeproto(newno->parent), (INTBIG)newno->geom);
979 				}
980 				if (stopping(STOPREASONREPLACE)) break;
981 			}
982 			ttyputmsg(_("All %ld %s nodes in cell %s replaced with %s"), total,
983 				describenodeproto(oldntype), describenodeproto(ni->parent), describenodeproto(np));
984 		} else if (connected)
985 		{
986 			/* replace all connected to this in the cell if "connected" used */
987 			for(lni = curcell->firstnodeinst; lni != NONODEINST; lni = lni->nextnodeinst)
988 				if (lni->proto == oldntype)
989 			{
990 				for(pi = lni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
991 				{
992 					for(rni = curcell->firstnodeinst; rni != NONODEINST; rni = rni->nextnodeinst)
993 					{
994 						if (rni->temp1 == 0) continue;
995 						for(opi = rni->firstportarcinst; opi != NOPORTARCINST; opi = opi->nextportarcinst)
996 						{
997 							if (pi->conarcinst->network == opi->conarcinst->network) break;
998 						}
999 						if (opi != NOPORTARCINST) break;
1000 					}
1001 					if (rni != NONODEINST) break;
1002 				}
1003 				if (pi == NOPORTARCINST) continue;
1004 
1005 				/* disallow replacing if lock is on */
1006 				if (us_cantedit(curcell, lni, TRUE)) continue;
1007 
1008 				newno = us_replacenodeinst(lni, np, ignoreportnames, allowmissingports);
1009 				if (newno != NONODEINST)
1010 				{
1011 					total++;
1012 					formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1013 						describenodeproto(newno->parent), (INTBIG)newno->geom);
1014 				}
1015 				if (stopping(STOPREASONREPLACE)) break;
1016 			}
1017 			ttyputmsg(_("All %ld %s nodes connected to this replaced with %s"), total,
1018 				describenodeproto(oldntype), describenodeproto(np));
1019 		} else ttyputmsg(_("Node %s replaced with %s"), describenodeproto(oldntype),
1020 			describenodeproto(np));
1021 
1022 		/* clean up */
1023 		us_setnodeproto(np);
1024 		us_setmultiplehighlight(returninfstr(infstr), FALSE);
1025 	} else
1026 	{
1027 		/* get arc to be replaced */
1028 		ai = firstgeom->entryaddr.ai;
1029 
1030 		/* disallow replacement if lock is on */
1031 		if (us_cantedit(ai->parent, NONODEINST, TRUE)) return;
1032 
1033 		/* get arcproto to replace it with */
1034 		if (count == 0)
1035 		{
1036 			count = ttygetparam(M_("Arc name: "), &us_replacep, MAXPARS, par);
1037 			if (count == 0)
1038 			{
1039 				us_abortedmsg();
1040 				return;
1041 			}
1042 		}
1043 		ap = getarcproto(par[0]);
1044 		if (ap == NOARCPROTO)
1045 		{
1046 			us_abortcommand(_("Nothing called '%s'"), par[0]);
1047 			return;
1048 		}
1049 
1050 		/* sanity check */
1051 		oldatype = ai->proto;
1052 		if (oldatype == ap)
1053 		{
1054 			us_abortcommand(_("Arc already of type %s"), describearcproto(ap));
1055 			return;
1056 		}
1057 
1058 		/* get any arguments to the replace */
1059 		connected = thiscell = thislibrary = universal = nodeswitharcs = FALSE;
1060 		while (count > 1)
1061 		{
1062 			len = estrlen(pt = par[1]);
1063 			if (namesamen(pt, x_("connected"), len) == 0) connected = TRUE;
1064 			if (namesamen(pt, x_("this-cell"), len) == 0) thiscell = TRUE;
1065 			if (namesamen(pt, x_("this-library"), len) == 0) thislibrary = TRUE;
1066 			if (namesamen(pt, x_("universally"), len) == 0) universal = TRUE;
1067 			if (namesamen(pt, x_("nodes-too"), len) == 0) nodeswitharcs = TRUE;
1068 			par++;
1069 			count--;
1070 		}
1071 
1072 		/* special case when replacing nodes, too */
1073 		if (nodeswitharcs)
1074 		{
1075 			if (thislibrary)
1076 			{
1077 				for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1078 					us_replaceallarcs(np, list, ap, FALSE, TRUE);
1079 			} else
1080 			{
1081 				us_replaceallarcs(ai->parent, list, ap, connected, thiscell);
1082 			}
1083 			return;
1084 		}
1085 
1086 		/* remove highlighting */
1087 		us_clearhighlightcount();
1088 
1089 		/* replace the arcinst */
1090 		infstr = initinfstr();
1091 		for(ai = curcell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1092 			ai->temp1 = 0;
1093 		for(i=0; list[i] != NOGEOM; i++)
1094 		{
1095 			geom = list[i];
1096 			if (geom->entryisnode) continue;
1097 			ai = geom->entryaddr.ai;
1098 			if (ai->proto != oldatype) continue;
1099 			startobjectchange((INTBIG)ai, VARCINST);
1100 			onlynewar = replacearcinst(ai, ap);
1101 			if (onlynewar == NOARCINST)
1102 			{
1103 				us_abortcommand(_("%s does not fit in the place of %s"), describearcproto(ap),
1104 					describearcproto(oldatype));
1105 				(void)returninfstr(infstr);
1106 				return;
1107 			}
1108 			endobjectchange((INTBIG)onlynewar, VARCINST);
1109 			onlynewar->temp1 = 1;
1110 			formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1111 				describenodeproto(onlynewar->parent), (INTBIG)onlynewar->geom);
1112 		}
1113 
1114 		/* do additional replacements if requested */
1115 		total = 1;
1116 		if (universal)
1117 		{
1118 			/* replace in all cells of library if "universally" used */
1119 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1120 				for(cell = lib->firstnodeproto; cell != NONODEPROTO;
1121 					cell = cell->nextnodeproto)
1122 			{
1123 				for(lai = cell->firstarcinst; lai != NOARCINST; lai = lai->nextarcinst)
1124 					if (lai->proto == oldatype)
1125 				{
1126 					/* disallow replacing if lock is on */
1127 					if (us_cantedit(cell, NONODEINST, TRUE)) continue;
1128 
1129 					startobjectchange((INTBIG)lai, VARCINST);
1130 					newar = replacearcinst(lai, ap);
1131 					if (newar != NOARCINST)
1132 					{
1133 						total++;
1134 						formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1135 							describenodeproto(newar->parent), (INTBIG)newar->geom);
1136 						endobjectchange((INTBIG)newar, VARCINST);
1137 					}
1138 					if (stopping(STOPREASONREPLACE)) break;
1139 				}
1140 			}
1141 			ttyputmsg(_("All %ld %s arcs in the library replaced with %s"), total,
1142 				describearcproto(oldatype), describearcproto(ap));
1143 		} else if (thislibrary)
1144 		{
1145 			/* replace throughout this library if "this-library" used */
1146 			for(cell = el_curlib->firstnodeproto; cell != NONODEPROTO;
1147 				cell = cell->nextnodeproto)
1148 			{
1149 				for(lai = cell->firstarcinst; lai != NOARCINST; lai = lai->nextarcinst)
1150 					if (lai->proto == oldatype)
1151 				{
1152 					startobjectchange((INTBIG)lai, VARCINST);
1153 					newar = replacearcinst(lai, ap);
1154 					if (newar != NOARCINST)
1155 					{
1156 						total++;
1157 						formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1158 							describenodeproto(newar->parent), (INTBIG)newar->geom);
1159 						endobjectchange((INTBIG)newar, VARCINST);
1160 					}
1161 					if (stopping(STOPREASONREPLACE)) break;
1162 				}
1163 			}
1164 			ttyputmsg(_("All %ld %s arcs in library %s replaced with %s"), total,
1165 				describearcproto(oldatype), el_curlib->libname, describearcproto(ap));
1166 		} else if (thiscell)
1167 		{
1168 			/* replace throughout this cell if "this-cell" used */
1169 			for(lai = curcell->firstarcinst; lai != NOARCINST; lai = lai->nextarcinst)
1170 				if (lai->proto == oldatype)
1171 			{
1172 				startobjectchange((INTBIG)lai, VARCINST);
1173 				newar = replacearcinst(lai, ap);
1174 				if (newar != NOARCINST)
1175 				{
1176 					total++;
1177 					formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1178 						describenodeproto(newar->parent), (INTBIG)newar->geom);
1179 					endobjectchange((INTBIG)newar, VARCINST);
1180 				}
1181 				if (stopping(STOPREASONREPLACE)) break;
1182 			}
1183 			ttyputmsg(_("All %ld %s arcs in cell %s replaced with %s"), total,
1184 				describearcproto(oldatype), describenodeproto(ai->parent), describearcproto(ap));
1185 		} else if (connected)
1186 		{
1187 			/* replace all connected to this if "connected" used */
1188 			for(lai = curcell->firstarcinst; lai != NOARCINST; lai = lai->nextarcinst)
1189 				if (lai->proto == oldatype)
1190 			{
1191 				for(rai = curcell->firstarcinst; rai != NOARCINST; rai = rai->nextarcinst)
1192 				{
1193 					if (rai->temp1 == 0) continue;
1194 					if (lai->network != rai->network) continue;
1195 					startobjectchange((INTBIG)lai, VARCINST);
1196 					newar = replacearcinst(lai, ap);
1197 					if (newar != NOARCINST)
1198 					{
1199 						total++;
1200 						formatinfstr(infstr, x_("CELL=%s FROM=0%lo;-1;0\n"),
1201 							describenodeproto(newar->parent), (INTBIG)newar->geom);
1202 						endobjectchange((INTBIG)newar, VARCINST);
1203 					}
1204 				}
1205 				if (stopping(STOPREASONREPLACE)) break;
1206 			}
1207 			ttyputmsg(_("All %ld %s arcs connected to this replaced with %s"), total,
1208 				describearcproto(oldatype), describearcproto(ap));
1209 		} else ttyputmsg(_("Arc %s replaced with %s"), describearcproto(oldatype),
1210 			describearcproto(ap));
1211 
1212 		/* clean up */
1213 		us_setarcproto(ap, TRUE);
1214 		us_setmultiplehighlight(returninfstr(infstr), FALSE);
1215 	}
1216 }
1217 
us_rotate(INTBIG count,CHAR * par[])1218 void us_rotate(INTBIG count, CHAR *par[])
1219 {
1220 	REGISTER NODEINST *ni, *theni, *subni, **nilist, **newnilist;
1221 	REGISTER NODEPROTO *np;
1222 	REGISTER PORTPROTO *pp, *thepp;
1223 	REGISTER ARCINST *ai, **ailist, **newailist;
1224 	REGISTER GEOM **list;
1225 	REGISTER VARIABLE *var;
1226 	REGISTER HIGHLIGHT *high;
1227 	REGISTER INTBIG amt, startangle, endangle, rotatemore;
1228 	INTBIG xstart, ystart, xend, yend, gx, gy, cx, cy, rotcx, rotcy, aicount,
1229 		x, y, thex, they, newnicount;
1230 	REGISTER INTBIG lx, hx, ly, hy, nicount, dist, bestdist, i, j;
1231 	XARRAY transtz, rot, transfz, t1, t2;
1232 
1233 	/* handle interactive rotation */
1234 	if (count == 1 && namesamen(par[0], x_("interactively"), estrlen(par[0])) == 0)
1235 	{
1236 		ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
1237 		if (ni == NONODEINST)
1238 		{
1239 			us_abortcommand(_("Must highlight one node for interactive rotation"));
1240 			return;
1241 		}
1242 
1243 		/* disallow rotating if lock is on */
1244 		if (us_cantedit(ni->parent, ni, TRUE)) return;
1245 
1246 		/* save highlighting */
1247 		us_pushhighlight();
1248 		us_clearhighlightcount();
1249 
1250 		if (us_demandxy(&xstart, &ystart)) return;
1251 		us_rotateinit(ni);
1252 		trackcursor(FALSE, us_ignoreup, us_rotatebegin, us_rotatedown,
1253 			us_stopandpoponchar, us_dragup, TRACKDRAGGING);
1254 		if (el_pleasestop != 0) return;
1255 		if (us_demandxy(&xend, &yend)) return;
1256 		startangle = figureangle((ni->lowx+ni->highx)/2, (ni->lowy+ni->highy)/2, xstart, ystart);
1257 		endangle = figureangle((ni->lowx+ni->highx)/2, (ni->lowy+ni->highy)/2, xend, yend);
1258 		if (startangle == endangle)
1259 		{
1260 			ttyputverbose(M_("Null node rotation"));
1261 			us_pophighlight(FALSE);
1262 			return;
1263 		}
1264 		if (ni->transpose == 0) amt = endangle - startangle; else
1265 			amt = startangle - endangle;
1266 		while (amt < 0) amt += 3600;
1267 		while (amt > 3600) amt -= 3600;
1268 
1269 		/* do the rotation */
1270 		startobjectchange((INTBIG)ni, VNODEINST);
1271 		modifynodeinst(ni, 0, 0, 0, 0, amt, 0);
1272 		endobjectchange((INTBIG)ni, VNODEINST);
1273 
1274 		/* restore highlighting */
1275 		us_pophighlight(TRUE);
1276 		return;
1277 	}
1278 
1279 	/* determine rotation amount */
1280 	if (count < 1)
1281 	{
1282 		ttyputusage(x_("rotate ANGLE"));
1283 		return;
1284 	}
1285 	amt = atofr(par[0]);
1286 	amt = amt * 10 / WHOLE;
1287 	rotatemore = 0;
1288 	if (count >= 2 && namesamen(par[1], x_("more"), estrlen(par[1])) == 0)
1289 	{
1290 		count--;
1291 		par++;
1292 		rotatemore++;
1293 	}
1294 
1295 	/* get all highlighted objects for rotation */
1296 	list = us_gethighlighted(WANTNODEINST|WANTARCINST, 0, 0);
1297 	if (list[0] == NOGEOM)
1298 	{
1299 		us_abortcommand(_("Must highlight node(s) to be rotated"));
1300 		return;
1301 	}
1302 	np = geomparent(list[0]);
1303 
1304 	/* disallow rotating if lock is on */
1305 	if (us_cantedit(np, NONODEINST, TRUE)) return;
1306 
1307 	/* figure out which nodes get rotated */
1308 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1309 		ni->temp1 = 0;
1310 	nicount = 0;
1311 	theni = NONODEINST;
1312 	lx = ly = hx = hy = 0;
1313 	for(i=0; list[i] != NOGEOM; i++)
1314 	{
1315 		if (!list[i]->entryisnode) continue;
1316 		ni = list[i]->entryaddr.ni;
1317 		if (us_cantedit(np, ni, TRUE)) return;
1318 		ni->temp1 = 1;
1319 		if (nicount == 0)
1320 		{
1321 			lx = ni->lowx;   hx = ni->highx;
1322 			ly = ni->lowy;   hy = ni->highy;
1323 		} else
1324 		{
1325 			if (ni->lowx < lx) lx = ni->lowx;
1326 			if (ni->highx > hx) hx = ni->highx;
1327 			if (ni->lowy < ly) ly = ni->lowy;
1328 			if (ni->highy > hy) hy = ni->highy;
1329 		}
1330 		theni = ni;
1331 		nicount++;
1332 	}
1333 
1334 	/* must be at least 1 node */
1335 	if (nicount <= 0)
1336 	{
1337 		us_abortcommand(_("Must select at least 1 node for rotation"));
1338 		return;
1339 	}
1340 
1341 	/* if multiple nodes, find the center one */
1342 	if (nicount > 1)
1343 	{
1344 		theni = NONODEINST;
1345 		bestdist = MAXINTBIG;
1346 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1347 		{
1348 			if (ni->temp1 == 0) continue;
1349 			dist = computedistance((lx+hx)/2, (ly+hy)/2, (ni->lowx+ni->highx)/2,
1350 				(ni->lowy+ni->highy)/2);
1351 
1352 			/* LINTED "bestdist" used in proper order */
1353 			if (theni == NONODEINST || dist < bestdist)
1354 			{
1355 				theni = ni;
1356 				bestdist = dist;
1357 			}
1358 		}
1359 	}
1360 
1361 	/* compute rotation, given the node */
1362 	if (amt == 0)
1363 	{
1364 		ttyputverbose(M_("Null rotation"));
1365 		return;
1366 	}
1367 
1368 	/* handle rotation about the grab point */
1369 	i = estrlen(par[1]);
1370 	if (count >= 2 && namesamen(par[1], x_("sensibly"), i) == 0)
1371 	{
1372 		if (nicount == 1)
1373 		{
1374 			if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
1375 			{
1376 				par[1] = x_("about-trace-point");
1377 			} else
1378 			{
1379 				if (theni->proto->primindex == 0)
1380 				{
1381 					var = getvalkey((INTBIG)theni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
1382 					if (var != NOVARIABLE)
1383 					{
1384 						par[1] = x_("about-grab-point");
1385 					}
1386 				}
1387 			}
1388 		}
1389 	}
1390 	if (count >= 2 && namesamen(par[1], x_("about-grab-point"), i) == 0 && i >= 7)
1391 	{
1392 		if (nicount > 1)
1393 		{
1394 			us_abortcommand(_("Must highlight one node for rotation about the grab-point"));
1395 			return;
1396 		}
1397 		ni = theni;
1398 
1399 		/* disallow rotating if lock is on */
1400 		if (us_cantedit(ni->parent, ni, TRUE)) return;
1401 
1402 		/* find the grab point */
1403 		corneroffset(ni, ni->proto, ni->rotation, ni->transpose, &gx, &gy, FALSE);
1404 		gx += ni->lowx;   gy += ni->lowy;
1405 
1406 		/* build transformation for this operation */
1407 		transid(transtz);   transtz[2][0] = -gx;   transtz[2][1] = -gy;
1408 		makeangle(amt, 0, rot);
1409 		transid(transfz);   transfz[2][0] = gx;    transfz[2][1] = gy;
1410 		transmult(transtz, rot, t1);
1411 		transmult(t1, transfz, t2);
1412 		cx = (ni->lowx+ni->highx)/2;   cy = (ni->lowy+ni->highy)/2;
1413 		xform(cx, cy, &gx, &gy, t2);
1414 		gx -= cx;   gy -= cy;
1415 
1416 		/* save highlighting */
1417 		us_pushhighlight();
1418 		us_clearhighlightcount();
1419 
1420 		/* do the rotation */
1421 		startobjectchange((INTBIG)ni, VNODEINST);
1422 
1423 		/* rotate and translate */
1424 		modifynodeinst(ni, gx, gy, gx, gy, amt, 0);
1425 
1426 		/* end change */
1427 		endobjectchange((INTBIG)ni, VNODEINST);
1428 
1429 		/* restore highlighting */
1430 		us_pophighlight(TRUE);
1431 		return;
1432 	}
1433 
1434 	/* handle rotation about a trace point */
1435 	if (count >= 2 && namesamen(par[1], x_("about-trace-point"), i) == 0 && i >= 7)
1436 	{
1437 		if (nicount > 1)
1438 		{
1439 			us_abortcommand(_("Must highlight one node for rotation about an outline point"));
1440 			return;
1441 		}
1442 		ni = theni;
1443 
1444 		/* disallow rotating if lock is on */
1445 		if (us_cantedit(ni->parent, ni, TRUE)) return;
1446 
1447 		/* get the trace information */
1448 		var = gettrace(ni);
1449 		if (var == NOVARIABLE)
1450 		{
1451 			us_abortcommand(_("Highlighted node must have outline information"));
1452 			return;
1453 		}
1454 
1455 		/* find the pivot point */
1456 		high = us_getonehighlight();
1457 		i = high->frompoint;   if (i != 0) i--;
1458 		makerot(ni, t1);
1459 		gx = (ni->highx + ni->lowx) / 2;
1460 		gy = (ni->highy + ni->lowy) / 2;
1461 		xform(((INTBIG *)var->addr)[i*2]+gx, ((INTBIG *)var->addr)[i*2+1]+gy, &gx, &gy, t1);
1462 
1463 		/* build transformation for this operation */
1464 		transid(transtz);   transtz[2][0] = -gx;   transtz[2][1] = -gy;
1465 		makeangle(amt, 0, rot);
1466 		transid(transfz);   transfz[2][0] = gx;    transfz[2][1] = gy;
1467 		transmult(transtz, rot, t1);
1468 		transmult(t1, transfz, t2);
1469 		cx = (ni->lowx+ni->highx)/2;   cy = (ni->lowy+ni->highy)/2;
1470 		xform(cx, cy, &gx, &gy, t2);
1471 		gx -= cx;   gy -= cy;
1472 
1473 		/* save highlighting */
1474 		us_pushhighlight();
1475 		us_clearhighlightcount();
1476 
1477 		/* do the rotation */
1478 		startobjectchange((INTBIG)ni, VNODEINST);
1479 
1480 		/* rotate and translate */
1481 		modifynodeinst(ni, gx, gy, gx, gy, amt, 0);
1482 
1483 		/* end change */
1484 		endobjectchange((INTBIG)ni, VNODEINST);
1485 
1486 		/* restore highlighting */
1487 		us_pophighlight(TRUE);
1488 		return;
1489 	}
1490 
1491 	/* see which nodes already connect to the main rotation node (theni) */
1492 	for(ni = theni->parent->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1493 		ni->temp1 = 0;
1494 	theni->temp1 = 1;
1495 	for(ai = theni->parent->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1496 		ai->temp1 = 0;
1497 	for(i=0; list[i] != NOGEOM; i++)
1498 	{
1499 		if (list[i]->entryisnode) continue;
1500 		ai = list[i]->entryaddr.ai;
1501 		ai->temp1 = 1;
1502 	}
1503 	us_spreadrotateconnection(theni);
1504 
1505 	/* now make sure that it is all connected */
1506 	aicount = newnicount = 0;
1507 	nilist = 0;
1508 	ailist = 0;
1509 	for(i=0; list[i] != NOGEOM; i++)
1510 	{
1511 		if (!list[i]->entryisnode) continue;
1512 		ni = list[i]->entryaddr.ni;
1513 		if (ni == theni) continue;
1514 		if (ni->temp1 != 0) continue;
1515 
1516 		thepp = theni->proto->firstportproto;
1517 		if (thepp == NOPORTPROTO)
1518 		{
1519 			/* no port on the cell: create one */
1520 			subni = newnodeinst(gen_univpinprim, theni->proto->lowx, theni->proto->highx,
1521 				theni->proto->lowy, theni->proto->highy, 0, 0, theni->proto);
1522 			if (subni == NONODEINST) break;
1523 			thepp = newportproto(theni->proto, subni, subni->proto->firstportproto, x_("temp"));
1524 			if (thepp == NOPORTPROTO) break;
1525 
1526 			/* add to the list of temporary nodes */
1527 			newnilist = (NODEINST **)emalloc((newnicount+1) * (sizeof (NODEINST *)), el_tempcluster);
1528 			if (newnilist == 0) break;
1529 
1530 			/* LINTED "nilist" used in proper order */
1531 			for(j=0; j<newnicount; j++) newnilist[j] = nilist[j];
1532 			if (newnicount > 0) efree((CHAR *)nilist);
1533 			nilist = newnilist;
1534 			nilist[newnicount] = subni;
1535 			newnicount++;
1536 		}
1537 		pp = ni->proto->firstportproto;
1538 		if (pp != NOPORTPROTO)
1539 		{
1540 			portposition(theni, thepp, &thex, &they);
1541 			portposition(ni, pp, &x, &y);
1542 			ai = newarcinst(gen_invisiblearc, 0, FIXED, theni, thepp, thex, they,
1543 				ni, pp, x, y, np);
1544 			if (ai == NOARCINST) break;
1545 			endobjectchange((INTBIG)ai, VARCINST);
1546 
1547 			newailist = (ARCINST **)emalloc((aicount+1) * (sizeof (ARCINST *)), el_tempcluster);
1548 			if (newailist == 0) break;
1549 
1550 			/* LINTED "ailist" used in proper order */
1551 			for(j=0; j<aicount; j++) newailist[j] = ailist[j];
1552 			if (aicount > 0) efree((CHAR *)ailist);
1553 			ailist = newailist;
1554 			ailist[aicount] = ai;
1555 			aicount++;
1556 		}
1557 	}
1558 
1559 	/* make all selected arcs temporarily rigid */
1560 	us_modarcbits(6, FALSE, x_(""), list);
1561 
1562 	/* save highlighting */
1563 	us_pushhighlight();
1564 	us_clearhighlightcount();
1565 
1566 	/* see if there is a snap point */
1567 	if (!us_getonesnappoint(&rotcx, &rotcy))
1568 	{
1569 		/* no snap point, use center of node */
1570 		rotcx = (theni->lowx + theni->highx) / 2;
1571 		rotcy = (theni->lowy + theni->highy) / 2;
1572 	}
1573 
1574 	/* build transformation for this operation */
1575 	transid(transtz);   transtz[2][0] = -rotcx;   transtz[2][1] = -rotcy;
1576 	makeangle(amt, 0, rot);
1577 	transid(transfz);   transfz[2][0] = rotcx;    transfz[2][1] = rotcy;
1578 	transmult(transtz, rot, t1);
1579 	transmult(t1, transfz, t2);
1580 	cx = (theni->lowx+theni->highx)/2;   cy = (theni->lowy+theni->highy)/2;
1581 	xform(cx, cy, &gx, &gy, t2);
1582 	gx -= cx;   gy -= cy;
1583 
1584 	/* do the rotation */
1585 	startobjectchange((INTBIG)theni, VNODEINST);
1586 	modifynodeinst(theni, gx, gy, gx, gy, amt, 0);
1587 	endobjectchange((INTBIG)theni, VNODEINST);
1588 
1589 	/* delete intermediate arcs used to constrain */
1590 	for(i=0; i<aicount; i++)
1591 	{
1592 		startobjectchange((INTBIG)ailist[i], VARCINST);
1593 		(void)killarcinst(ailist[i]);
1594 	}
1595 	if (aicount > 0) efree((CHAR *)ailist);
1596 
1597 	/* delete intermediate nodes used to constrain */
1598 	for(i=0; i<newnicount; i++)
1599 	{
1600 		(void)killportproto(nilist[i]->parent, nilist[i]->firstportexpinst->exportproto);
1601 		(void)killnodeinst(nilist[i]);
1602 	}
1603 	if (newnicount > 0) efree((CHAR *)nilist);
1604 
1605 	/* restore highlighting */
1606 	us_pophighlight(TRUE);
1607 }
1608 
1609 #define MAXPORTTYPE 16
1610 
us_show(INTBIG count,CHAR * par[])1611 void us_show(INTBIG count, CHAR *par[])
1612 {
1613 	CHAR line[100], *activity, *name, *colorname, *colorsymbol, *dumpfilename, *truename;
1614 	REGISTER CHAR *pt, *matchspec, *str, **keybindings, **buttonbindings, *pt1, *pt2, save,
1615 		*prefix, **dummylibs, **newdummylibs;
1616 	INTBIG plx, ply, phx, phy, keyindex[NUMKEYS], idummy32, porttype[MAXPORTTYPE], len, wid, xp, yp,
1617 		boundspecial, shortcols, numtypes, num_found;
1618 	INTSML boundkey;
1619 	REGISTER INTBIG i, j, k, l, m, tot, *equivlist, *buslist, lx, hx, ly, hy,
1620 		verbose, maxlen, total, columns, rows, key, but, menu, popup, lambda,
1621 		shortcolwidth, shortrows, x, y, fun, keytotal, unnamed, dummylibcount;
1622 	REGISTER BOOLEAN graphiclist, graphiclistlocal, first, notbelow, placeholders,
1623 		recursivenodes, givedates, contentslist, summarize, editlist;
1624 	REGISTER NODEINST *ni;
1625 	REGISTER NODEPROTO *np, *wnp, **sortindex;
1626 	REGISTER PORTPROTO *pp, **pplist, *opp, **sortedbuslist;
1627 	REGISTER PORTARCINST *pi;
1628 	REGISTER PORTEXPINST *pe;
1629 	REGISTER ARCINST *ai;
1630 	REGISTER ARCPROTO *ap;
1631 	REGISTER POPUPMENU *pm, *wantpm;
1632 	REGISTER USERCOM *rb;
1633 	REGISTER HIGHLIGHT *high;
1634 	REGISTER LIBRARY *lib, *olib;
1635 	REGISTER VIEW *v;
1636 	REGISTER WINDOWPART *w;
1637 	REGISTER TECHNOLOGY *tech;
1638 	REGISTER VARIABLE *var, *varkey, *varbutton;
1639 	REGISTER NETWORK *net;
1640 	FILE *dumpfile;
1641 	CONSTRAINT *con;
1642 	COMMANDBINDING commandbinding;
1643 	extern COMCOMP us_showp;
1644 	REGISTER void *infstr;
1645 
1646 	if (count == 0)
1647 	{
1648 		count = ttygetparam(M_("Show option: "), &us_showp, MAXPARS, par);
1649 		if (count == 0)
1650 		{
1651 			us_abortedmsg();
1652 			return;
1653 		}
1654 	}
1655 	l = estrlen(pt = par[0]);
1656 
1657 	if (namesamen(pt, x_("tools"), l) == 0 && l >= 1)
1658 	{
1659 		ttyputmsg(_(" Which Tool       Information"));
1660 		for(i=0; i<el_maxtools; i++)
1661 		{
1662 			infstr = initinfstr();
1663 			if ((el_tools[i].toolstate&TOOLON) == 0) addstringtoinfstr(infstr, _("Off")); else
1664 				addstringtoinfstr(infstr, _("On"));
1665 			if ((el_tools[i].toolstate&TOOLBG) != 0) addstringtoinfstr(infstr, _(", Background"));
1666 			if ((el_tools[i].toolstate&TOOLFIX) != 0) addstringtoinfstr(infstr, _(", Correcting"));
1667 			if ((el_tools[i].toolstate&TOOLLANG) != 0) addstringtoinfstr(infstr, _(", Interpreted"));
1668 			if ((el_tools[i].toolstate&TOOLINCREMENTAL) != 0) addstringtoinfstr(infstr, _(", Incremental"));
1669 			if ((el_tools[i].toolstate&TOOLANALYSIS) != 0) addstringtoinfstr(infstr, _(", Analysis"));
1670 			if ((el_tools[i].toolstate&TOOLSYNTHESIS) != 0) addstringtoinfstr(infstr, _(", Synthesis"));
1671 			ttyputmsg(x_("%-16s %s"), el_tools[i].toolname, returninfstr(infstr));
1672 		}
1673 		return;
1674 	}
1675 
1676 	if (namesamen(pt, x_("bindings"), l) == 0 && l >= 1)
1677 	{
1678 		if (count <= 1)
1679 		{
1680 			ttyputusage(x_("show bindings key|menu|button|popup|all|short"));
1681 			return;
1682 		}
1683 		l = estrlen(pt = par[1]);
1684 
1685 		if (namesamen(pt, x_("short"), l) == 0 && l >= 1)
1686 		{
1687 			varkey = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
1688 			varbutton = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_buttons_key);
1689 			if (varkey == NOVARIABLE || varbutton == NOVARIABLE)
1690 			{
1691 				ttyputerr(M_("Cannot find key and button bindings"));
1692 				return;
1693 			}
1694 			keytotal = getlength(varkey);
1695 			keybindings = (CHAR **)varkey->addr;
1696 			buttonbindings = (CHAR **)varbutton->addr;
1697 
1698 			/* print the button bindings */
1699 			j = buttoncount();
1700 			if (j > 0)
1701 			{
1702 				infstr = initinfstr();
1703 				for(i=0; i<(MESSAGESWIDTH-25)/2; i++) addtoinfstr(infstr, '-');
1704 				addstringtoinfstr(infstr, M_(" Single Button Commands: "));
1705 				for(i=0; i<(MESSAGESWIDTH-25)/2; i++) addtoinfstr(infstr, '-');
1706 				ttyputmsg(x_("%s"), returninfstr(infstr));
1707 
1708 				/* count the number of bound buttons, compute longest name */
1709 				for(i=0, k=0, j=0; i<buttoncount(); i++)
1710 				{
1711 					us_parsebinding(buttonbindings[i], &commandbinding);
1712 					if (*commandbinding.command != 0)
1713 					{
1714 						k++;
1715 						for(l=0; commandbinding.command[l] != 0; l++)
1716 							if (commandbinding.command[l] == ' ') break;
1717 						j = maxi(j, l + estrlen(buttonname(i, &idummy32)));
1718 					}
1719 					us_freebindingparse(&commandbinding);
1720 				}
1721 
1722 				/* compute number of rows and columns */
1723 				shortcols = mini(MESSAGESWIDTH / (j+4), k);
1724 				shortcolwidth = MESSAGESWIDTH / shortcols;
1725 				shortrows = (k+shortcols-1) / shortcols;
1726 
1727 				/* print the buttons */
1728 				i = -1;
1729 				for(j=0; j<shortrows; j++)
1730 				{
1731 					infstr = initinfstr();
1732 					for(m=0; m<shortcols; m++)
1733 					{
1734 						/* find next bound button */
1735 						for (;;)
1736 						{
1737 							i++;
1738 							if (i >= buttoncount()) break;
1739 							us_parsebinding(buttonbindings[i], &commandbinding);
1740 							if (*commandbinding.command != 0) break;
1741 							us_freebindingparse(&commandbinding);
1742 						}
1743 						if (i >= buttoncount()) break;
1744 
1745 						/* place button name */
1746 						pt = buttonname(i, &idummy32);
1747 						addstringtoinfstr(infstr, pt);
1748 						addstringtoinfstr(infstr, x_(": "));
1749 						k = estrlen(pt);
1750 
1751 						/* place command name */
1752 						for(l=0; commandbinding.command[l] != 0; l++)
1753 							if (commandbinding.command[l] == ' ') break;
1754 								else addtoinfstr(infstr, commandbinding.command[l]);
1755 						us_freebindingparse(&commandbinding);
1756 						k += l;
1757 
1758 						/* pad out the field if not at the end */
1759 						if (m<shortcols-1)
1760 							for(k = k+4; k < shortcolwidth; k++)
1761 								addtoinfstr(infstr, ' ');
1762 					}
1763 					ttyputmsg(x_("%s"), returninfstr(infstr));
1764 				}
1765 			}
1766 
1767 			/* print the key bindings */
1768 			infstr = initinfstr();
1769 			for(i=0; i<(MESSAGESWIDTH-22)/2; i++) addtoinfstr(infstr, '-');
1770 			addstringtoinfstr(infstr, M_(" Single Key Commands: "));
1771 			for(i=0; i<(MESSAGESWIDTH-22)/2; i++) addtoinfstr(infstr, '-');
1772 			ttyputmsg(x_("%s"), returninfstr(infstr));
1773 
1774 			/* count the number of bound keys, compute longest name */
1775 			for(i=0, k=0, j=0; i<keytotal; i++)
1776 			{
1777 				keyindex[i] = -1;
1778 				pt = us_getboundkey(keybindings[i], &boundkey, &boundspecial);
1779 				us_parsebinding(pt, &commandbinding);
1780 				if (*commandbinding.command != 0)
1781 				{
1782 					keyindex[i] = k++;
1783 					for(l=0; commandbinding.command[l] != 0; l++)
1784 						if (commandbinding.command[l] == ' ') break;
1785 					j = maxi(j, l);
1786 				}
1787 				us_freebindingparse(&commandbinding);
1788 			}
1789 
1790 			/* compute number of rows and columns */
1791 			shortcols = MESSAGESWIDTH / (j+8);
1792 			shortcolwidth = MESSAGESWIDTH / shortcols;
1793 			shortrows = (k+shortcols-1) / shortcols;
1794 
1795 			/* print the keys */
1796 			for(j=0; j<shortrows; j++)
1797 			{
1798 				infstr = initinfstr();
1799 				for(m=0; m<shortcols; m++) for(i=0; i<keytotal; i++)
1800 					if (keyindex[i] == m*shortrows+j)
1801 				{
1802 					/* place key name */
1803 					str = us_getboundkey(keybindings[i], &boundkey, &boundspecial);
1804 					pt = us_describeboundkey(boundkey, boundspecial, 1);
1805 					for(k=estrlen(pt); k<8; k++) addtoinfstr(infstr, ' ');
1806 					addstringtoinfstr(infstr, pt);
1807 					addtoinfstr(infstr, ' ');
1808 
1809 					/* place command name */
1810 					us_parsebinding(str, &commandbinding);
1811 					for(l=0; commandbinding.command[l] != 0; l++)
1812 						if (commandbinding.command[l] == ' ') break; else
1813 							addtoinfstr(infstr, commandbinding.command[l]);
1814 					us_freebindingparse(&commandbinding);
1815 
1816 					/* pad out the field if not at the end */
1817 					if (m<shortcols-1)
1818 						for(k=l+4; k < shortcolwidth; k++)
1819 							addtoinfstr(infstr, ' ');
1820 				}
1821 				ttyputmsg(x_("%s"), returninfstr(infstr));
1822 			}
1823 			return;
1824 		}
1825 
1826 		key = but = menu = popup = 0;
1827 		if (namesamen(pt, x_("all"), l) == 0 && l >= 1)
1828 		{
1829 			but++;   key++;   menu++;   popup++;
1830 		}
1831 		if (namesamen(pt, x_("key"), l) == 0 && l >= 1) key++;
1832 		if (namesamen(pt, x_("menu"), l) == 0 && l >= 1) menu++;
1833 		if (namesamen(pt, x_("button"), l) == 0 && l >= 1) but++;
1834 		if (namesamen(pt, x_("popup"), l) == 0 && l >= 1) popup++;
1835 
1836 		if (key == 0 && but == 0 && menu == 0 && popup == 0)
1837 		{
1838 			ttyputbadusage(x_("show bindings"));
1839 			return;
1840 		}
1841 
1842 		/* if key bindings are requested, list them */
1843 		if (key)
1844 		{
1845 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_keys_key);
1846 			if (var == NOVARIABLE)
1847 			{
1848 				ttyputerr(M_("Cannot find key binding attributes"));
1849 				return;
1850 			}
1851 			l = getlength(var);
1852 			for(i=0; i<l; i++)
1853 			{
1854 				pt = us_getboundkey(((CHAR **)var->addr)[i], &boundkey, &boundspecial);
1855 				us_parsebinding(pt, &commandbinding);
1856 				if (*commandbinding.command != 0)
1857 					ttyputmsg(M_("Key %s: %s"), us_describeboundkey(boundkey, boundspecial, 1),
1858 						commandbinding.command);
1859 				us_freebindingparse(&commandbinding);
1860 			}
1861 		}
1862 
1863 		/* if button bindings are requested, list them */
1864 		if (but)
1865 		{
1866 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_buttons_key);
1867 			if (var == NOVARIABLE)
1868 			{
1869 				ttyputerr(M_("Cannot find button binding attributes"));
1870 				return;
1871 			}
1872 			l = getlength(var);
1873 			for(i=0; i<l; i++)
1874 			{
1875 				us_parsebinding(((CHAR **)var->addr)[i], &commandbinding);
1876 				if (*commandbinding.command != 0) ttyputmsg(_("Button %s: %s"),
1877 					buttonname(i, &idummy32), commandbinding.command);
1878 				us_freebindingparse(&commandbinding);
1879 			}
1880 		}
1881 
1882 		/* if menu bindings are requested, list them */
1883 		if (menu)
1884 		{
1885 			var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
1886 			if (var == NOVARIABLE)
1887 			{
1888 				ttyputerr(M_("Cannot find menu binding attributes"));
1889 				return;
1890 			}
1891 			for(x=0; x<us_menux; x++) for(y=0; y<us_menuy; y++)
1892 			{
1893 				if (us_menupos <= 1)
1894 					str = ((CHAR **)var->addr)[y * us_menux + x]; else
1895 						str = ((CHAR **)var->addr)[x * us_menuy + y];
1896 				us_parsebinding(str, &commandbinding);
1897 				infstr = initinfstr();
1898 				formatinfstr(infstr, M_("Menu row %ld column %ld: "), y, x);
1899 				if (*commandbinding.command == 0) addstringtoinfstr(infstr, _("NOT DEFINED")); else
1900 					addstringtoinfstr(infstr, commandbinding.command);
1901 				if (commandbinding.menumessage != 0)
1902 				{
1903 					addstringtoinfstr(infstr, x_(" [message=\""));
1904 					addstringtoinfstr(infstr, commandbinding.menumessage);
1905 					addstringtoinfstr(infstr, x_("\"]"));
1906 				} else if (commandbinding.nodeglyph != NONODEPROTO)
1907 				{
1908 					addstringtoinfstr(infstr, x_(" [node="));
1909 					addstringtoinfstr(infstr, describenodeproto(commandbinding.nodeglyph));
1910 					addtoinfstr(infstr, ']');
1911 				} else if (commandbinding.arcglyph != NOARCPROTO)
1912 				{
1913 					addstringtoinfstr(infstr, x_(" [arc="));
1914 					addstringtoinfstr(infstr, describearcproto(commandbinding.arcglyph));
1915 					addtoinfstr(infstr, ']');
1916 				}
1917 				if (commandbinding.backgroundcolor != 0)
1918 				{
1919 					if (ecolorname(commandbinding.backgroundcolor, &colorname, &colorsymbol))
1920 						colorname = x_("**UNKNOWN**");
1921 					formatinfstr(infstr, x_(" [background=%s]"), colorname);
1922 				}
1923 				ttyputmsg(x_("%s"), returninfstr(infstr));
1924 				us_freebindingparse(&commandbinding);
1925 			}
1926 		}
1927 
1928 		/* if popup menu bindings are requested, list them */
1929 		if (popup)
1930 		{
1931 			if (count <= 2) wantpm = NOPOPUPMENU; else
1932 			{
1933 				wantpm = us_getpopupmenu(par[2]);
1934 				if (wantpm == NOPOPUPMENU)
1935 				{
1936 					us_abortcommand(M_("Cannot find popup menu '%s'"), par[2]);
1937 					return;
1938 				}
1939 			}
1940 
1941 			for(pm = us_firstpopupmenu; pm != NOPOPUPMENU; pm = pm->nextpopupmenu)
1942 			{
1943 				if (wantpm != NOPOPUPMENU && wantpm != pm) continue;
1944 				ttyputmsg(_("Popup menu %s has %ld entries:"), pm->name, pm->total);
1945 				for(i=0; i<pm->total; i++)
1946 				{
1947 					rb = pm->list[i].response;
1948 					infstr = initinfstr();
1949 					formatinfstr(infstr, M_("Entry %ld: "), i);
1950 					if (rb->active < 0) addstringtoinfstr(infstr, M_("NOT DEFINED")); else
1951 					{
1952 						addstringtoinfstr(infstr, rb->comname);
1953 						us_appendargs(infstr, rb);
1954 					}
1955 					if (rb->message != 0)
1956 						formatinfstr(infstr, x_(" [message=\"%s\"]"), rb->message);
1957 					ttyputmsg(x_("   %s"), returninfstr(infstr));
1958 				}
1959 			}
1960 		}
1961 		return;
1962 	}
1963 
1964 	if (namesamen(pt, x_("coverage"), l) == 0 && l >= 2)
1965 	{
1966 		/* determine coverage of the metal and polysilicon layers */
1967 		np = us_needcell();
1968 		if (np == NONODEPROTO) return;
1969 		us_showlayercoverage(np);
1970 		return;
1971 	}
1972 
1973 	if (namesamen(pt, x_("dates"), l) == 0 && l >= 1)
1974 	{
1975 		if (count < 2)
1976 		{
1977 			np = us_needcell();
1978 			if (np == NONODEPROTO) return;
1979 		} else
1980 		{
1981 			np = getnodeproto(par[1]);
1982 			if (np == NONODEPROTO || np->primindex != 0)
1983 			{
1984 				us_abortcommand(_("No such cell: %s"), par[1]);
1985 				return;
1986 			}
1987 		}
1988 
1989 		/* give requested info */
1990 		if (np->creationdate == 0)
1991 			ttyputmsg(_("Cell %s has no recorded creation date"), describenodeproto(np)); else
1992 				ttyputmsg(_("Cell %s was created %s"), describenodeproto(np),
1993 					timetostring((time_t)np->creationdate));
1994 		ttyputmsg(_("Version %ld was last revised %s"), np->version, timetostring((time_t)np->revisiondate));
1995 		return;
1996 	}
1997 
1998 	if (namesamen(pt, x_("error"), l) == 0 && l >= 2)
1999 	{
2000 		if (count < 2)
2001 		{
2002 			ttyputusage(x_("show error (next | last)"));
2003 			return;
2004 		}
2005 		l = estrlen(pt = par[1]);
2006 		if (namesamen(pt, x_("next"), l) == 0)
2007 		{
2008 			ttyputmsg(x_("%s"), reportnexterror(1, 0, 0));
2009 			return;
2010 		}
2011 		if (namesamen(pt, x_("last"), l) == 0)
2012 		{
2013 			ttyputmsg(x_("%s"), reportpreverror());
2014 			return;
2015 		}
2016 		ttyputbadusage(x_("show error"));
2017 		return;
2018 	}
2019 
2020 	if (namesamen(pt, x_("environment"), l) == 0 && l >= 2)
2021 	{
2022 		ttyputmsg(_("This is Electric, version %s"), el_version);
2023 		pt = languagename();
2024 		if (pt != NOSTRING) ttyputmsg(_("Includes built-in %s"), pt);
2025 		ttyputmsg(_("Default library directory is %s"), el_libdir);
2026 
2027 		if (count > 1 && namesamen(par[1], x_("authors"), estrlen(par[1])) == 0)
2028 		{
2029 			ttyputmsg(_("Electric was written by Steven M. Rubin"));
2030 			ttyputmsg(_("   and a cast of thousands:"));
2031 			for(i=0; us_castofthousands[i].name != 0; i++)
2032 			ttyputmsg(x_("      %s"), us_castofthousands[i].name);
2033 		}
2034 		return;
2035 	}
2036 
2037 	if (namesamen(pt, x_("cells"), l) == 0 && l >= 2)
2038 	{
2039 		editlist = givedates = graphiclist = graphiclistlocal = FALSE;
2040 		contentslist = notbelow = recursivenodes = placeholders = FALSE;
2041 		dumpfilename = 0;
2042 		np = getcurcell();
2043 		lib = el_curlib;
2044 		matchspec = 0;
2045 		while (count >= 2)
2046 		{
2047 			l = estrlen(pt = par[1]);
2048 			if (namesamen(pt, x_("dates"), l) == 0) givedates = TRUE; else
2049 			if (namesamen(pt, x_("edit"), l) == 0) editlist = TRUE; else
2050 			if (namesamen(pt, x_("graphically"), l) == 0) graphiclist = TRUE; else
2051 			if (namesamen(pt, x_("from-here-graphically"), l) == 0 && l >= 2) graphiclistlocal = TRUE; else
2052 			if (namesamen(pt, x_("placeholders"), l) == 0) placeholders = TRUE; else
2053 			if (namesamen(pt, x_("contained-in-this"), l) == 0) contentslist = TRUE; else
2054 			if (namesamen(pt, x_("recursive-nodes"), l) == 0) recursivenodes = TRUE; else
2055 			if (namesamen(pt, x_("not-below"), l) == 0) notbelow = TRUE; else
2056 			if (namesamen(pt, x_("matching"), l) == 0)
2057 			{
2058 				if (count < 3)
2059 				{
2060 					ttyputusage(x_("show cells matching MATCHSPEC"));
2061 					return;
2062 				}
2063 				if (matchspec != 0)
2064 				{
2065 					us_abortcommand(_("Can only have one 'matching' clause"));
2066 					return;
2067 				}
2068 				matchspec = par[2];
2069 				for(pt = matchspec; *pt != 0; pt++)
2070 					if (*pt == ':') break;
2071 				if (*pt == ':')
2072 				{
2073 					*pt++ = 0;
2074 					lib = getlibrary(matchspec);
2075 					if (lib == NOLIBRARY)
2076 					{
2077 						us_abortcommand(_("Cannot find library '%s'"), matchspec);
2078 						return;
2079 					}
2080 					matchspec = pt;
2081 				}
2082 				par++;
2083 				count--;
2084 			} else if (namesamen(pt, x_("library"), l) == 0)
2085 			{
2086 				if (count < 3)
2087 				{
2088 					ttyputusage(x_("show cells library LIBNAME"));
2089 					return;
2090 				}
2091 				lib = getlibrary(par[2]);
2092 				if (lib == NOLIBRARY)
2093 				{
2094 					us_abortcommand(_("No library called %s"), par[2]);
2095 					return;
2096 				}
2097 				par++;
2098 				count--;
2099 			} else if (namesamen(pt, x_("file"), l) == 0 && l >= 2)
2100 			{
2101 				if (count < 3)
2102 				{
2103 					ttyputusage(x_("show cells file FILENAME"));
2104 					return;
2105 				}
2106 				dumpfilename = par[2];
2107 				par++;
2108 				count--;
2109 			} else
2110 			{
2111 				ttyputbadusage(x_("show cells"));
2112 				return;
2113 			}
2114 			par++;
2115 			count--;
2116 		}
2117 
2118 		if (contentslist)
2119 		{
2120 			if (givedates || editlist || graphiclist ||
2121 				matchspec != 0 || dumpfilename != 0 || recursivenodes ||
2122 				placeholders || graphiclistlocal || notbelow)
2123 					ttyputerr(_("Other options for 'contained-in-this' ignored"));
2124 
2125 			wnp = us_needcell();
2126 			if (wnp == NONODEPROTO) return;
2127 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
2128 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2129 					np->temp1 = 0;
2130 			for(ni = wnp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2131 			{
2132 				np = ni->proto;
2133 				if (np->primindex != 0) continue;
2134 				np->temp1++;
2135 			}
2136 			first = TRUE;
2137 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
2138 				for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2139 					if (np->temp1 != 0)
2140 			{
2141 				if (first)
2142 					ttyputmsg(_("Cell instances appearing in %s"), describenodeproto(wnp));
2143 				first = FALSE;
2144 				infstr = initinfstr();
2145 				formatinfstr(infstr, _("   %ld instances of %s at"), np->temp1,
2146 					describenodeproto(np));
2147 				lambda = lambdaofcell(wnp);
2148 				for(ni = wnp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2149 				{
2150 					if (ni->proto != np) continue;
2151 					us_getnodedisplayposition(ni, &xp, &yp);
2152 					formatinfstr(infstr, x_(" (%s,%s)"), latoa(xp, lambda), latoa(yp, lambda));
2153 				}
2154 				ttyputmsg(x_("%s"), returninfstr(infstr));
2155 			}
2156 			if (first)
2157 				ttyputmsg(_("There are no cell instances in %s"), describenodeproto(wnp));
2158 			return;
2159 		}
2160 
2161 		/* graph the cells if requested */
2162 		if (graphiclist || graphiclistlocal)
2163 		{
2164 			if (givedates || editlist || contentslist || matchspec != 0 ||
2165 				dumpfilename != 0 || recursivenodes || placeholders || notbelow)
2166 					ttyputerr(M_("Other options for 'graphically' ignored"));
2167 			np = NONODEPROTO;
2168 			if (graphiclistlocal)
2169 			{
2170 				np = us_needcell();
2171 				if (np == NONODEPROTO) return;
2172 			}
2173 			us_graphcells(np);
2174 			return;
2175 		}
2176 
2177 		/* show contents of cell if requested */
2178 		if (recursivenodes)
2179 		{
2180 			if (givedates || editlist || contentslist ||
2181 				matchspec != 0 || dumpfilename != 0 || graphiclist ||
2182 				placeholders || graphiclistlocal || notbelow)
2183 					ttyputerr(M_("Other options for 'recursive-nodes' ignored"));
2184 			np = us_needcell();
2185 			if (np == NONODEPROTO) return;
2186 			us_describecontents(np);
2187 			return;
2188 		}
2189 
2190 		/* show all cells not used below this one */
2191 		if (notbelow)
2192 		{
2193 			if (givedates || editlist || contentslist || matchspec != 0 ||
2194 				dumpfilename != 0 || graphiclist || placeholders ||
2195 				graphiclistlocal || recursivenodes)
2196 					ttyputerr(M_("Other options for 'not-below' ignored"));
2197 			wnp = us_needcell();
2198 			if (wnp == NONODEPROTO) return;
2199 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2200 			{
2201 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2202 					np->temp1 = 0;
2203 			}
2204 			us_recursivemark(wnp);
2205 			first = TRUE;
2206 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2207 			{
2208 				if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
2209 				i = 0;
2210 				infstr = 0;
2211 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2212 				{
2213 					if (np->temp1 != 0) continue;
2214 					if (i == 0)
2215 					{
2216 						infstr = initinfstr();
2217 						formatinfstr(infstr, _("  From library %s:"), lib->libname);
2218 					}
2219 					formatinfstr(infstr, x_(" %s"), nldescribenodeproto(np));
2220 					i++;
2221 				}
2222 				if (i != 0)
2223 				{
2224 					if (first)
2225 					{
2226 						ttyputmsg(_("These cells are not used by %s"), describenodeproto(wnp));
2227 						first = FALSE;
2228 					}
2229 					ttyputmsg(x_("%s"), returninfstr(infstr));
2230 				}
2231 			}
2232 			return;
2233 		}
2234 
2235 		/* show placeholders (cells created to handle cross-library input errors) if requested */
2236 		if (placeholders)
2237 		{
2238 			if (givedates || editlist || contentslist || matchspec != 0 ||
2239 				dumpfilename != 0 || recursivenodes || notbelow)
2240 					ttyputerr(M_("Other options for 'placeholders' ignored"));
2241 			i = 0;
2242 			for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2243 			{
2244 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2245 				{
2246 					var = getval((INTBIG)np, VNODEPROTO, VSTRING, x_("IO_true_library"));
2247 					if (var == NOVARIABLE) continue;
2248 					ttyputmsg(_("Cell %s is a placeholder"), describenodeproto(np));
2249 					i++;
2250 				}
2251 			}
2252 			if (i == 0)
2253 				ttyputmsg(_("There are no placeholder cells"));
2254 			return;
2255 		}
2256 
2257 		/* allocate array for sorting entries */
2258 		sortindex = us_sortlib(lib, matchspec);
2259 		if (sortindex == 0)
2260 		{
2261 			ttyputnomemory();
2262 			return;
2263 		}
2264 
2265 		/* compute the longest cell name and the number of cells */
2266 		maxlen = 0;   total = 0;
2267 		for(i=0; sortindex[i] != NONODEPROTO; i++)
2268 		{
2269 			l = estrlen(nldescribenodeproto(sortindex[i]));
2270 			maxlen = maxi(maxlen, l);
2271 			total++;
2272 		}
2273 
2274 		/* short list in columns */
2275 		if (!givedates && !editlist)
2276 		{
2277 			if (dumpfilename != 0)
2278 				ttyputerr(_("Cannot write to file unless 'dates' option specified"));
2279 			ttyputmsg(_("----- Cells in library %s -----"), lib->libname);
2280 			maxlen += 2;  columns = MESSAGESWIDTH / maxlen;
2281 			if (columns <= 0) columns = 1;
2282 			rows = (total + columns - 1) / columns;
2283 			for(j=0; j<rows; j++)
2284 			{
2285 				infstr = initinfstr();
2286 				for(k=0; k<columns; k++)
2287 				{
2288 					i = j + k*rows;
2289 					if (i >= total) continue;
2290 					np = sortindex[i];
2291 					pt = nldescribenodeproto(np);
2292 					addstringtoinfstr(infstr, pt);
2293 					l = estrlen(pt);
2294 					if (k != columns-1)
2295 						for(i=l; i<maxlen; i++) addtoinfstr(infstr, ' ');
2296 				}
2297 				ttyputmsg(x_("%s"), returninfstr(infstr));
2298 			}
2299 
2300 			/* free the sort list */
2301 			efree((CHAR *)sortindex);
2302 			return;
2303 		}
2304 
2305 		/* full list with dates */
2306 		if (givedates)
2307 		{
2308 			/* create the dump file if requested */
2309 			if (dumpfilename != 0)
2310 			{
2311 				dumpfile = xopen(dumpfilename, el_filetypetext|FILETYPEWRITE, 0, &truename);
2312 				if (dumpfile == 0)
2313 				{
2314 					us_abortcommand(_("Cannot write %s"), dumpfilename);
2315 					return;
2316 				}
2317 				pt = timetostring(getcurrenttime());
2318 				efprintf(dumpfile, _("List of cells in library %s created on %s\n"), lib->libname, pt);
2319 				efprintf(dumpfile, _("Cell\tVersion\tCreation date\tRevision Date\tSize\tUsage\tLock\tInst-lock\tCell-lib\tDRC\tNCC\n"));
2320 				for(j=0; j<total; j++)
2321 					efprintf(dumpfile, x_("%s\n"), us_makecellline(sortindex[j], -1));
2322 				xclose(dumpfile);
2323 				ttyputmsg(_("Wrote %s"), truename);
2324 			} else
2325 			{
2326 				maxlen = maxi(maxlen+2, 7);
2327 				infstr = initinfstr();
2328 				addstringtoinfstr(infstr, _("Cell"));
2329 				for(i=5; i<maxlen; i++) addtoinfstr(infstr, '-');
2330 				addstringtoinfstr(infstr, _("Version-----Creation date"));
2331 				addstringtoinfstr(infstr, _("---------Revision Date------------Size-------Usage-L-I-C-D-N"));
2332 				ttyputmsg(x_("%s"), returninfstr(infstr));
2333 				for(j=0; j<total; j++)
2334 					ttyputmsg(x_("%s"), us_makecellline(sortindex[j], maxlen));
2335 			}
2336 
2337 			/* free the sort list */
2338 			efree((CHAR *)sortindex);
2339 			return;
2340 		}
2341 
2342 		/* editable list */
2343 		if (editlist)
2344 		{
2345 			if (dumpfilename != 0)
2346 				ttyputerr(_("Cannot write to file when 'edit' option specified"));
2347 			w = us_wantnewwindow(0);
2348 			if (w == NOWINDOWPART) return;
2349 			infstr = initinfstr();
2350 			us_describeeditor(&name);
2351 			addstringtoinfstr(infstr, name);
2352 			addstringtoinfstr(infstr, _(" editor of cell names in library "));
2353 			addstringtoinfstr(infstr, lib->libname);
2354 			if (us_makeeditor(w, returninfstr(infstr), &idummy32, &idummy32) == NOWINDOWPART) return;
2355 			w->charhandler = us_celledithandler;
2356 			us_suspendgraphics(w);
2357 			maxlen = maxi(maxlen+2, 7);
2358 			infstr = initinfstr();
2359 			addstringtoinfstr(infstr, _("Cell"));
2360 			for(i=5; i<maxlen; i++) addtoinfstr(infstr, '-');
2361 			addstringtoinfstr(infstr, _("Version-----Creation date"));
2362 			addstringtoinfstr(infstr, _("---------Revision Date------------Size-------Usage-L-I-C-D-N"));
2363 			us_addline(w, 0, returninfstr(infstr));
2364 			for(j=0; j<total; j++)
2365 				us_addline(w, j+1, us_makecellline(sortindex[j], maxlen));
2366 			us_resumegraphics(w);
2367 			us_describeeditor(&name);
2368 			if (namesame(name, x_("emacs")) == 0)
2369 				ttyputmsg(_("Use M(=) to edit the cell on the current line"));
2370 
2371 			/* free the sort list */
2372 			efree((CHAR *)sortindex);
2373 			return;
2374 		}
2375 	}
2376 
2377 	if (namesamen(pt, x_("history"), l) == 0 && l >= 1)
2378 	{
2379 		if (count <= 1)
2380 		{
2381 			showhistorylist(-1);
2382 			return;
2383 		}
2384 		showhistorylist(myatoi(par[1]));
2385 		return;
2386 	}
2387 
2388 	if (namesamen(pt, x_("libraries"), l) == 0 && l >= 1)
2389 	{
2390 		ttyputmsg(_("----- Libraries -----"));
2391 		k = 0;
2392 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2393 		{
2394 			if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
2395 			infstr = initinfstr();
2396 			addstringtoinfstr(infstr, lib->libname);
2397 			if ((lib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) != 0)
2398 			{
2399 				addtoinfstr(infstr, '*');
2400 				k++;
2401 			}
2402 			if (estrcmp(lib->libname, lib->libfile) != 0)
2403 				formatinfstr(infstr, _(" (disk file: %s)"), lib->libfile);
2404 			ttyputmsg(x_("%s"), returninfstr(infstr));
2405 
2406 			/* see if there are dependencies */
2407 			dummylibcount = 0;
2408 			dummylibs = 0;
2409 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
2410 				olib->temp1 = 0;
2411 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2412 			{
2413 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2414 				{
2415 					if (ni->proto->primindex != 0) continue;
2416 					var = getval((INTBIG)ni->proto, VNODEPROTO, VSTRING, x_("IO_true_library"));
2417 					if (var != NOVARIABLE)
2418 					{
2419 						pt = (CHAR *)var->addr;
2420 						for(i=0; i<dummylibcount; i++)
2421 							if (namesame(pt, dummylibs[i]) == 0) break;
2422 						if (i >= dummylibcount)
2423 						{
2424 							newdummylibs = (CHAR **)emalloc((dummylibcount+1) * (sizeof (CHAR *)),
2425 								us_tool->cluster);
2426 							if (newdummylibs == 0) return;
2427 							for(i=0; i<dummylibcount; i++)
2428 								newdummylibs[i] = dummylibs[i];
2429 							(void)allocstring(&newdummylibs[dummylibcount], pt, us_tool->cluster);
2430 							if (dummylibcount > 0) efree((CHAR *)dummylibs);
2431 							dummylibs = newdummylibs;
2432 							dummylibcount++;
2433 						}
2434 					}
2435 					ni->proto->lib->temp1 = 1;
2436 				}
2437 			}
2438 			for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
2439 			{
2440 				if (olib == lib) continue;
2441 				if (olib->temp1 == 0) continue;
2442 				infstr = initinfstr();
2443 				formatinfstr(infstr, _("   Depends on library %s from cell(s):"),
2444 					olib->libname);
2445 				for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2446 				{
2447 					for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2448 					{
2449 						if (ni->proto->primindex != 0) continue;
2450 						if (ni->proto->lib == olib) break;
2451 					}
2452 					if (ni == NONODEINST) continue;
2453 					formatinfstr(infstr, x_(" %s"), nldescribenodeproto(np));
2454 				}
2455 				ttyputmsg(x_("%s"), returninfstr(infstr));
2456 			}
2457 			if (dummylibcount > 0)
2458 			{
2459 				for(i=0; i<dummylibcount; i++)
2460 				{
2461 					infstr = initinfstr();
2462 					formatinfstr(infstr, _("   Wanted unknown library %s from cell(s):"),
2463 						dummylibs[i]);
2464 					for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2465 					{
2466 						for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2467 						{
2468 							if (ni->proto->primindex != 0) continue;
2469 							var = getval((INTBIG)ni->proto, VNODEPROTO, VSTRING, x_("IO_true_library"));
2470 							if (var == NOVARIABLE) continue;
2471 							pt = (CHAR *)var->addr;
2472 							if (namesame(pt, dummylibs[i]) == 0) break;
2473 						}
2474 						if (ni == NONODEINST) continue;
2475 						formatinfstr(infstr, x_(" %s"), nldescribenodeproto(np));
2476 					}
2477 					ttyputmsg(x_("%s"), returninfstr(infstr));
2478 					efree(dummylibs[i]);
2479 				}
2480 				efree((CHAR *)dummylibs);
2481 			}
2482 		}
2483 		if (k != 0) ttyputmsg(_("   (* means library has changed)"));
2484 		return;
2485 	}
2486 
2487 	if (namesamen(pt, x_("macros"), l) == 0 && l >= 1)
2488 	{
2489 		if (count >= 2)
2490 		{
2491 			var = us_getmacro(par[1]);
2492 			if (var != NOVARIABLE)
2493 			{
2494 				us_printmacro(var);
2495 				return;
2496 			}
2497 			us_abortcommand(_("No macro named %s"), par[1]);
2498 			return;
2499 		}
2500 		us_printmacros();
2501 		return;
2502 	}
2503 
2504 	if (namesamen(pt, x_("networks"), l) == 0 && l >= 1)
2505 	{
2506 		np = us_needcell();
2507 		if (np == NONODEPROTO) return;
2508 		total = 0;
2509 		unnamed = 0;
2510 		for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
2511 		{
2512 			if (net->namecount == 0 && net->globalnet < 0)
2513 			{
2514 				unnamed++;
2515 				continue;
2516 			}
2517 			infstr = initinfstr();
2518 			formatinfstr(infstr, x_("'%s'"), describenetwork(net));
2519 			if (net->buswidth > 1)
2520 			{
2521 				formatinfstr(infstr, _(" (bus with %d signals)"), net->buswidth);
2522 			}
2523 			if (net->arccount == 0 && net->portcount == 0 && net->buslinkcount == 0)
2524 				addstringtoinfstr(infstr, _(" not connected")); else
2525 			{
2526 				addstringtoinfstr(infstr, _(" connected on"));
2527 				if (net->arccount != 0)
2528 				{
2529 					formatinfstr(infstr, x_(" %d %s"), net->arccount, makeplural(_("arc"), net->arccount));
2530 				}
2531 				if (net->portcount != 0)
2532 				{
2533 					if (net->arccount != 0) addstringtoinfstr(infstr, x_(", "));
2534 					formatinfstr(infstr, x_(" %d %s"), net->portcount, makeplural(_("port"), net->portcount));
2535 				}
2536 				if (net->buslinkcount > 0)
2537 				{
2538 					if (net->arccount != 0 || net->portcount != 0) addstringtoinfstr(infstr, x_(", "));
2539 					formatinfstr(infstr, x_(" %d "), net->buslinkcount);
2540 					if (net->buslinkcount != 1) addstringtoinfstr(infstr, _("busses")); else
2541 						addstringtoinfstr(infstr, _("bus"));
2542 				}
2543 			}
2544 			ttyputmsg(_("Network %s"), returninfstr(infstr));
2545 			total++;
2546 		}
2547 		if (unnamed != 0)
2548 		{
2549 			if (total == 0)
2550 			{
2551 				ttyputmsg(_("Cell has %ld unnamed %s"), unnamed,
2552 					makeplural(x_("network"), unnamed));
2553 			} else
2554 			{
2555 				ttyputmsg(_("Plus %ld unnamed %s"), unnamed, makeplural(x_("network"), unnamed));
2556 			}
2557 		} else
2558 		{
2559 			if (total == 0) ttyputmsg(_("There are no named networks"));
2560 		}
2561 		return;
2562 	}
2563 
2564 	if (namesamen(pt, x_("object"), l) == 0 && l >= 1)
2565 	{
2566 		verbose = 0;
2567 		if (count > 1)
2568 		{
2569 			l = estrlen(par[1]);
2570 			if (namesamen(par[1], x_("short"), l) == 0 && l >= 1) verbose = -1;
2571 			if (namesamen(par[1], x_("long"), l) == 0 && l >= 1) verbose = 1;
2572 		}
2573 
2574 		high = us_getonehighlight();
2575 		if (high == NOHIGHLIGHT) return;
2576 
2577 		if ((high->status&HIGHTYPE) == HIGHTEXT)
2578 		{
2579 			/* describe highlighted text */
2580 			if (high->fromvar != NOVARIABLE)
2581 			{
2582 				ttyputmsg(_("%s variable '%s' is on %s"), us_variableattributes(high->fromvar, -1),
2583 					describevariable(high->fromvar, -1, -1), geomname(high->fromgeom));
2584 				return;
2585 			}
2586 			if (high->fromport != NOPORTPROTO)
2587 			{
2588 				infstr = initinfstr();
2589 				activity = describeportbits(high->fromport->userbits);
2590 				if (*activity != 0)
2591 				{
2592 					formatinfstr(infstr, _("%s port name '%s' is on %s (label %s"), activity,
2593 						high->fromport->protoname, geomname(high->fromgeom),
2594 							us_describetextdescript(high->fromport->textdescript));
2595 				} else
2596 				{
2597 					formatinfstr(infstr, _("Port name '%s' is on %s (label %s"),
2598 						high->fromport->protoname, geomname(high->fromgeom),
2599 							us_describetextdescript(high->fromport->textdescript));
2600 				}
2601 				if ((high->fromport->userbits&PORTDRAWN) != 0)
2602 					addstringtoinfstr(infstr, _(",always-drawn"));
2603 				if ((high->fromport->userbits&BODYONLY) != 0)
2604 					addstringtoinfstr(infstr, _(",only-on-body"));
2605 				addstringtoinfstr(infstr, x_(") "));
2606 				ttyputmsg(x_("%s"), returninfstr(infstr));
2607 				return;
2608 			}
2609 			if (high->fromgeom->entryisnode)
2610 			{
2611 				ni = high->fromgeom->entryaddr.ni;
2612 				infstr = initinfstr();
2613 				formatinfstr(infstr, _("Cell name '%s' (label %s)"), describenodeproto(ni->proto),
2614 					us_describetextdescript(ni->textdescript));
2615 				ttyputmsg(x_("%s"), returninfstr(infstr));
2616 				return;
2617 			}
2618 		}
2619 		if ((high->status&HIGHTYPE) != HIGHFROM)
2620 		{
2621 			us_abortcommand(_("Find a single node or arc first"));
2622 			return;
2623 		}
2624 
2625 		/* describe a nodeinst */
2626 		if (high->fromgeom->entryisnode)
2627 		{
2628 			/* give basic information about nodeinst */
2629 			ni = high->fromgeom->entryaddr.ni;
2630 			np = ni->proto;
2631 			lambda = lambdaofnode(ni);
2632 			nodesizeoffset(ni, &plx, &ply, &phx, &phy);
2633 			infstr = initinfstr();
2634 			if (np->primindex != 0)
2635 			{
2636 				formatinfstr(infstr, _("Node %s is %sx%s"), describenodeinst(ni),
2637 					latoa(ni->highx-ni->lowx-plx-phx, lambda), latoa(ni->highy-ni->lowy-ply-phy, lambda));
2638 			} else
2639 			{
2640 				formatinfstr(infstr, _("Cell %s is %sx%s"), describenodeinst(ni),
2641 					latoa(ni->highx-ni->lowx-plx-phx, lambda), latoa(ni->highy-ni->lowy-ply-phy, lambda));
2642 			}
2643 
2644 			/* special case for serpentine transistors: print true size */
2645 			if (np->primindex != 0 && (np->userbits&HOLDSTRACE) != 0)
2646 			{
2647 				fun = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
2648 				if (fun == NPTRANMOS || fun == NPTRADMOS || fun == NPTRAPMOS)
2649 				{
2650 					var = gettrace(ni);
2651 					if (var != NOVARIABLE)
2652 					{
2653 						transistorsize(ni, &len, &wid);
2654 						if (len != -1 && wid != -1)
2655 							formatinfstr(infstr, _(" (actually %sx%s)"), latoa(len, lambda),
2656 								latoa(wid, lambda));
2657 					}
2658 				}
2659 			}
2660 			addstringtoinfstr(infstr, x_(", "));
2661 			if (ni->transpose != 0) addstringtoinfstr(infstr, _("transposed and "));
2662 			formatinfstr(infstr, _("rotated %s, center (%s,%s)"), frtoa(ni->rotation*WHOLE/10),
2663 				latoa((ni->highx+ni->lowx)/2, lambda), latoa((ni->highy+ni->lowy)/2, lambda));
2664 			ttyputmsg(x_("%s"), returninfstr(infstr));
2665 
2666 			/* reset the "chat" indicator on the port prototypes */
2667 			for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2668 				pp->temp1 = 0;
2669 
2670 			/* always describe the highlighted port */
2671 			if (high->fromport != NOPORTPROTO)
2672 				us_chatportproto(ni, high->fromport);
2673 
2674 			/* describe all arcs and ports if not short option */
2675 			if (verbose >= 0)
2676 			{
2677 				for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2678 					us_chatportproto(ni, pe->proto);
2679 				for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2680 					us_chatportproto(ni, pi->proto);
2681 			}
2682 
2683 			/* long option: describe tool information, variables, etc */
2684 			if (verbose > 0)
2685 			{
2686 				/* talk about every port in long option */
2687 				for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2688 					us_chatportproto(ni, pp);
2689 
2690 				/* print tool information */
2691 				us_printnodetoolinfo(ni);
2692 
2693 				/* print variables */
2694 				for(i=0; i<ni->numvar; i++)
2695 					ttyputmsg(_("%s variable '%s' is %s"), us_variableattributes(&ni->firstvar[i], -1),
2696 						makename(ni->firstvar[i].key), describevariable(&ni->firstvar[i], -1, -1));
2697 
2698 				/* describe contents */
2699 				if (np->primindex == 0) us_describecontents(ni->proto);
2700 			}
2701 		} else if (!high->fromgeom->entryisnode)
2702 		{
2703 			/* print the basic information about the arcinst */
2704 			ai = high->fromgeom->entryaddr.ai;
2705 			lambda = lambdaofarc(ai);
2706 
2707 			/* compute the arc length and width */
2708 			wid = ai->width - arcwidthoffset(ai);
2709 			len = ai->length;
2710 			if ((ai->userbits&NOEXTEND) == 0) len += wid; else
2711 			{
2712 				if ((ai->userbits&NOTEND0) != 0) len += wid/2;
2713 				if ((ai->userbits&NOTEND1) != 0) len += wid/2;
2714 			}
2715 
2716 			/* build a string of constraints and properties */
2717 			infstr = initinfstr();
2718 			formatinfstr(infstr, _("%s arc is "), describearcinst(ai));
2719 			if (el_curconstraint == cla_constraint)
2720 			{
2721 				if (((ai->userbits&FIXED) == 0 || ai->changed == cla_changeclock+3) &&
2722 					ai->changed != cla_changeclock+2)
2723 				{
2724 					if (ai->changed == cla_changeclock+3) addstringtoinfstr(infstr, _("temporarily "));
2725 					addstringtoinfstr(infstr, _("stretchable, "));
2726 					if ((ai->userbits&FIXANG) == 0) addstringtoinfstr(infstr, _("not fixed-angle, ")); else
2727 						addstringtoinfstr(infstr, _("fixed-angle, "));
2728 					if ((ai->userbits&CANTSLIDE) != 0) addstringtoinfstr(infstr, _("nonslidable, ")); else
2729 						addstringtoinfstr(infstr, _("slidable, "));
2730 				} else
2731 				{
2732 					if (ai->changed == cla_changeclock+2) addstringtoinfstr(infstr, _("temporarily "));
2733 					addstringtoinfstr(infstr, _("rigid, "));
2734 				}
2735 			} else
2736 			{
2737 				pt = (CHAR *)(*(el_curconstraint->request))(x_("describearc"), (INTBIG)ai);
2738 				if (*pt != 0)
2739 					formatinfstr(infstr, _("constrained to %s, "));
2740 			}
2741 			if ((ai->userbits&ISNEGATED) != 0) addstringtoinfstr(infstr, _("negated, "));
2742 			if ((ai->userbits&ISDIRECTIONAL) != 0) addstringtoinfstr(infstr, _("directional, "));
2743 			if ((ai->userbits&(NOTEND0|NOTEND1)) != 0)
2744 			{
2745 				addstringtoinfstr(infstr, _("with "));
2746 				switch (ai->userbits & (NOTEND0|NOTEND1))
2747 				{
2748 					case NOTEND0:         addstringtoinfstr(infstr, _("tail"));             break;
2749 					case NOTEND1:         addstringtoinfstr(infstr, _("head"));             break;
2750 					case NOTEND0|NOTEND1: addstringtoinfstr(infstr, _("head and tail"));    break;
2751 				}
2752 				addstringtoinfstr(infstr, _(" skipped, "));
2753 			}
2754 			if ((ai->userbits&REVERSEEND) != 0) addstringtoinfstr(infstr, _("ends reversed, "));
2755 
2756 			/* add bus width */
2757 			if (ai->network != NONETWORK && ai->network->buswidth > 1)
2758 				formatinfstr(infstr, _("has %d signals, "), ai->network->buswidth);
2759 
2760 			/* add in width and length */
2761 			formatinfstr(infstr, _("%s wide and %s long"), latoa(wid, lambda), latoa(len, lambda));
2762 
2763 			/* if the arc is unnamed but on a network, report this */
2764 			var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
2765 			if (var == NOVARIABLE)
2766 			{
2767 				if (ai->network != NONETWORK && ai->network->namecount != 0)
2768 				{
2769 					formatinfstr(infstr, _(", on network %s"), describenetwork(ai->network));
2770 				}
2771 			}
2772 
2773 			/* print the message */
2774 			ttyputmsg(x_("%s"), returninfstr(infstr));
2775 
2776 			/* tell about the ends if default or long option */
2777 			if (verbose >= 0)
2778 			{
2779 				ttyputmsg(_("Tail on port %s of %s at (%s,%s) runs %ld degrees to"),
2780 					ai->end[0].portarcinst->proto->protoname, describenodeinst(ai->end[0].nodeinst),
2781 						latoa(ai->end[0].xpos, lambda), latoa(ai->end[0].ypos, lambda),
2782 							(ai->userbits & AANGLE) >> AANGLESH);
2783 				ttyputmsg(_("Head on port %s of %s at (%s,%s)"),
2784 					ai->end[1].portarcinst->proto->protoname, describenodeinst(ai->end[1].nodeinst),
2785 						latoa(ai->end[1].xpos, lambda), latoa(ai->end[1].ypos, lambda));
2786 			}
2787 
2788 			/* tell about tool values and variables if long option */
2789 			if (verbose > 0)
2790 			{
2791 				/* print tool information */
2792 				us_printarctoolinfo(ai);
2793 
2794 				/* print variables */
2795 				for(i=0; i<ai->numvar; i++)
2796 					ttyputmsg(_("%s variable '%s' is %s"), us_variableattributes(&ai->firstvar[i], -1),
2797 						makename(ai->firstvar[i].key), describevariable(&ai->firstvar[i], -1, -1));
2798 			}
2799 		}
2800 		return;
2801 	}
2802 
2803 	if (namesamen(pt, x_("ports"), l) == 0 && l >= 2)
2804 	{
2805 		np = us_needcell();
2806 		if (np == NONODEPROTO) return;
2807 		numtypes = 0;
2808 		summarize = TRUE;
2809 		if (count > 1) summarize = FALSE;
2810 		if (count == 1) par[count++] = x_("all");
2811 		for (i=1; i<count; i++)
2812 		{
2813 			l = estrlen(par[i]);
2814 			if (namesamen(par[i], x_("clock"), l) == 0 && l >= 1)
2815 			{
2816 				porttype[numtypes++] = CLKPORT;		/* basic clock */
2817 				porttype[numtypes++] = C1PORT;		/* clock phase 1 */
2818 				porttype[numtypes++] = C2PORT;		/* clock phase 2 */
2819 				porttype[numtypes++] = C3PORT;		/* clock phase 3 */
2820 				porttype[numtypes++] = C4PORT;		/* clock phase 4 */
2821 				porttype[numtypes++] = C5PORT;		/* clock phase 5 */
2822 				porttype[numtypes++] = C6PORT;		/* clock phase 6 */
2823 			} else if (namesamen(par[i], x_("input"), l) == 0 && l >= 1)
2824 				porttype[numtypes++] = INPORT;		/* input */
2825 			else if (namesamen(par[i], x_("output"), l) == 0 && l >= 1)
2826 				porttype[numtypes++] = OUTPORT;		/* output */
2827 			else if (namesamen(par[i], x_("bidirectional"), l) == 0 && l >= 1)
2828 				porttype[numtypes++] = BIDIRPORT;	/* bidirectional */
2829 			else if (namesamen(par[i], x_("power"), l) == 0 && l >= 1)
2830 				porttype[numtypes++] = PWRPORT;		/* power */
2831 			else if (namesamen(par[i], x_("ground"), l) == 0 && l >= 2)
2832 				porttype[numtypes++] = GNDPORT;		/* ground */
2833 			else if (namesamen(par[i], x_("reference"), l) == 0 && l >= 1)
2834 			{
2835 				porttype[numtypes++] = REFOUTPORT;	/* ref out */
2836 				porttype[numtypes++] = REFINPORT;	/* ref in */
2837 				porttype[numtypes++] = REFBASEPORT;	/* ref base */
2838 			} else if (namesamen(par[i], x_("generic"), l) == 0 && l >= 2)
2839 				porttype[numtypes++] = 0;
2840 			else if (namesamen(par[i], x_("all"), l) == 0 && l >= 1)
2841 			{
2842 				porttype[numtypes++] = 0;			/* generic */
2843 				porttype[numtypes++] = CLKPORT;		/* basic clock */
2844 				porttype[numtypes++] = C1PORT;		/* clock phase 1 */
2845 				porttype[numtypes++] = C2PORT;		/* clock phase 2 */
2846 				porttype[numtypes++] = C3PORT;		/* clock phase 3 */
2847 				porttype[numtypes++] = C4PORT;		/* clock phase 4 */
2848 				porttype[numtypes++] = C5PORT;		/* clock phase 5 */
2849 				porttype[numtypes++] = C6PORT;		/* clock phase 6 */
2850 				porttype[numtypes++] = INPORT;		/* input */
2851 				porttype[numtypes++] = OUTPORT;		/* output */
2852 				porttype[numtypes++] = BIDIRPORT;	/* bidirectional */
2853 				porttype[numtypes++] = PWRPORT;		/* power */
2854 				porttype[numtypes++] = GNDPORT;		/* ground */
2855 				porttype[numtypes++] = REFOUTPORT;	/* ref out */
2856 				porttype[numtypes++] = REFINPORT;	/* ref in */
2857 				porttype[numtypes++] = REFBASEPORT;	/* ref base */
2858 			} else
2859 			{
2860 				 ttyputbadusage(x_("show port"));
2861 				 return;
2862 			}
2863 		}
2864 
2865 		/* compute the associated cell to check */
2866 		wnp = contentsview(np);
2867 		if (wnp == NONODEPROTO) wnp = iconview(np);
2868 		if (wnp == np) wnp = NONODEPROTO;
2869 
2870 		/* count the number of exports */
2871 		num_found = 0;
2872 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2873 		{
2874 			m = pp->userbits & STATEBITS;
2875 			for(i=0; i<numtypes; i++) if (porttype[i] == m) break;
2876 			if (i >= numtypes) continue;
2877 			num_found++;
2878 		}
2879 		if (num_found == 0)
2880 		{
2881 			ttyputmsg(_("There are no exports on cell %s"), describenodeproto(np));
2882 			return;
2883 		}
2884 
2885 		/* make a list of exports */
2886 		pplist = (PORTPROTO **)emalloc(num_found * (sizeof (PORTPROTO *)), el_tempcluster);
2887 		if (pplist == 0) return;
2888 		equivlist = (INTBIG *)emalloc(num_found * SIZEOFINTBIG, el_tempcluster);
2889 		if (equivlist == 0) return;
2890 		buslist = (INTBIG *)emalloc(num_found * SIZEOFINTBIG, el_tempcluster);
2891 		if (buslist == 0) return;
2892 		num_found = 0;
2893 		for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2894 		{
2895 			m = pp->userbits & STATEBITS;
2896 			for(i=0; i<numtypes; i++) if (porttype[i] == m) break;
2897 			if (i >= numtypes) continue;
2898 			pplist[num_found] = pp;
2899 			equivlist[num_found] = -1;
2900 			buslist[num_found] = -1;
2901 			num_found++;
2902 		}
2903 
2904 		/* sort exports by name within type */
2905 		esort(pplist, num_found, sizeof (PORTPROTO *), us_exportnametypeascending);
2906 
2907 		/* if summarizing, make associations that combine exports */
2908 		if (summarize)
2909 		{
2910 			/* make associations among electrically equivalent exports */
2911 			for(j=0; j<num_found; j++)
2912 			{
2913 				if (equivlist[j] != -1 || buslist[j] != -1) continue;
2914 				for(k=j+1; k<num_found; k++)
2915 				{
2916 					if (equivlist[k] != -1 || buslist[k] != -1) continue;
2917 					if ((pplist[j]->userbits&STATEBITS) != (pplist[k]->userbits&STATEBITS))
2918 						break;
2919 					if (pplist[j]->network != pplist[k]->network) continue;
2920 					equivlist[k] = j;
2921 					equivlist[j] = -2;
2922 				}
2923 			}
2924 
2925 			/* make associations among bussed exports */
2926 			for(j=0; j<num_found; j++)
2927 			{
2928 				if (equivlist[j] != -1 || buslist[j] != -1) continue;
2929 				for(k=j+1; k<num_found; k++)
2930 				{
2931 					if (equivlist[k] != -1 || buslist[k] != -1) continue;
2932 					if ((pplist[j]->userbits&STATEBITS) != (pplist[k]->userbits&STATEBITS))
2933 						break;
2934 					pt1 = pplist[j]->protoname;
2935 					pt2 = pplist[k]->protoname;
2936 					for(;;)
2937 					{
2938 						if (tolower(*pt1) != tolower(*pt2)) break;
2939 						if (*pt1 == '[') break;
2940 						pt1++;   pt2++;
2941 					}
2942 					if (*pt1 != '[' || *pt2 != '[') continue;
2943 					buslist[k] = j;
2944 					buslist[j] = -2;
2945 				}
2946 			}
2947 		}
2948 
2949 		/* describe each export */
2950 		lambda = lambdaofcell(np);
2951 		ttyputmsg(_("----- Exports on cell %s -----"), describenodeproto(np));
2952 		for(j=0; j<num_found; j++)
2953 		{
2954 			if (equivlist[j] >= 0 || buslist[j] >= 0) continue;
2955 			pp = pplist[j];
2956 
2957 			/* reset flags for arcs that can connect */
2958 			for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
2959 				for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2960 					ap->temp1 = 0;
2961 
2962 			infstr = initinfstr();
2963 			activity = describeportbits(pp->userbits);
2964 			if (*activity == 0) activity = _("Unknown");
2965 			for(k=j+1; k<num_found; k++) if (equivlist[k] == j) break;
2966 			lx = hx = ly = hy = 0;
2967 			if (k < num_found)
2968 			{
2969 				/* many exports that are electrically equivalent */
2970 				formatinfstr(infstr, _("%s exports "), activity);
2971 				for(k=j; k<num_found; k++)
2972 				{
2973 					if (j != k && equivlist[k] != j) continue;
2974 					if (j != k) addstringtoinfstr(infstr, x_(", "));
2975 					opp = pplist[k];
2976 					formatinfstr(infstr, x_("'%s'"), opp->protoname);
2977 					portposition(opp->subnodeinst, opp->subportproto, &xp, &yp);
2978 					if (j == k)
2979 					{
2980 						lx = hx = xp;   ly = hy = yp;
2981 					} else
2982 					{
2983 						if (xp < lx) lx = xp;
2984 						if (xp > hx) hx = xp;
2985 						if (yp < ly) ly = yp;
2986 						if (yp > hy) hy = yp;
2987 					}
2988 					for(i=0; opp->connects[i] != NOARCPROTO; i++)
2989 						opp->connects[i]->temp1 = 1;
2990 				}
2991 				formatinfstr(infstr, _(" at (%s<=X<=%s, %s<=Y<=%s), electrically connected to"),
2992 					latoa(lx, lambda), latoa(hx, lambda), latoa(ly, lambda), latoa(hy, lambda));
2993 				us_addpossiblearcconnections(infstr);
2994 			} else
2995 			{
2996 				for(k=j+1; k<num_found; k++) if (buslist[k] == j) break;
2997 				if (k < num_found)
2998 				{
2999 					/* many exports from the same bus */
3000 					tot = 0;
3001 					for(k=j; k<num_found; k++)
3002 					{
3003 						if (j != k && buslist[k] != j) continue;
3004 						tot++;
3005 						opp = pplist[k];
3006 						portposition(opp->subnodeinst, opp->subportproto, &xp, &yp);
3007 						if (j == k)
3008 						{
3009 							lx = hx = xp;   ly = hy = yp;
3010 						} else
3011 						{
3012 							if (xp < lx) lx = xp;
3013 							if (xp > hx) hx = xp;
3014 							if (yp < ly) ly = yp;
3015 							if (yp > hy) hy = yp;
3016 						}
3017 						for(i=0; opp->connects[i] != NOARCPROTO; i++)
3018 							opp->connects[i]->temp1 = 1;
3019 					}
3020 					sortedbuslist = (PORTPROTO **)emalloc(tot * (sizeof (PORTPROTO *)),
3021 						el_tempcluster);
3022 					if (sortedbuslist == 0) return;
3023 					tot = 0;
3024 					sortedbuslist[tot++] = pplist[j];
3025 					for(k=j+1; k<num_found; k++)
3026 						if (buslist[k] == j) sortedbuslist[tot++] = pplist[k];
3027 
3028 					/* sort the bus by indices */
3029 					esort(pplist, tot, sizeof (PORTPROTO *), us_exportnameindexascending);
3030 
3031 					pt1 = sortedbuslist[0]->protoname;
3032 					while (*pt1 != 0 && *pt1 != '[') pt1++;
3033 					k = *pt1;   *pt1 = 0;
3034 					formatinfstr(infstr, _("%s ports '%s["), activity, sortedbuslist[0]->protoname);
3035 					*pt1 = (CHAR)k;
3036 					for(k=0; k<tot; k++)
3037 					{
3038 						if (k != 0) addstringtoinfstr(infstr, x_(","));
3039 						pt1 = sortedbuslist[k]->protoname;
3040 						while (*pt1 != 0 && *pt1 != '[') pt1++;
3041 						if (*pt1 == '[') pt1++;
3042 						while (*pt1 != 0 && *pt1 != ']') addtoinfstr(infstr, *pt1++);
3043 					}
3044 					formatinfstr(infstr, _("] at (%s<=X<=%s, %s<=Y<=%s), same bus, connects to"),
3045 						latoa(lx, lambda), latoa(hx, lambda), latoa(ly, lambda), latoa(hy, lambda));
3046 					us_addpossiblearcconnections(infstr);
3047 					efree((CHAR *)sortedbuslist);
3048 				} else
3049 				{
3050 					/* isolated export */
3051 					portposition(pp->subnodeinst, pp->subportproto, &xp, &yp);
3052 					formatinfstr(infstr, _("%s export '%s' at (%s, %s) connects to"), activity, pp->protoname,
3053 						latoa(xp, lambda), latoa(yp, lambda));
3054 					for(i=0; pp->connects[i] != NOARCPROTO; i++)
3055 						pp->connects[i]->temp1 = 1;
3056 					us_addpossiblearcconnections(infstr);
3057 
3058 					/* check for the export in the associated cell */
3059 					if (wnp != NONODEPROTO)
3060 					{
3061 						if (equivalentport(np, pp, wnp) == NOPORTPROTO)
3062 							formatinfstr(infstr, _(" *** no equivalent in %s"), describenodeproto(wnp));
3063 					}
3064 				}
3065 			}
3066 
3067 			str = returninfstr(infstr);
3068 			prefix = x_("");
3069 			while (estrlen(str) > 80)
3070 			{
3071 				for(i=80; i > 0; i--) if (str[i] == ' ' || str[i] == ',') break;
3072 				if (i <= 0) i = 80;
3073 				if (str[i] == ',') i++;
3074 				save = str[i];
3075 				str[i] = 0;
3076 				ttyputmsg(x_("%s%s"), prefix, str);
3077 				str[i] = save;
3078 				str = &str[i];
3079 				if (str[0] == ' ') str++;
3080 				prefix = x_("   ");
3081 			}
3082 			ttyputmsg(x_("%s%s"), prefix, str);
3083 		}
3084 		if (wnp != NONODEPROTO)
3085 		{
3086 			for(pp = wnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
3087 			{
3088 				m = pp->userbits & STATEBITS;
3089 				for(i=0; i<numtypes; i++) if (porttype[i] == m) break;
3090 				if (i >= numtypes) continue;
3091 				if (equivalentport(wnp, pp, np) == NOPORTPROTO)
3092 					ttyputmsg(_("*** Export %s, found in cell %s, is missing here"),
3093 						pp->protoname, describenodeproto(wnp));
3094 			}
3095 		}
3096 		efree((CHAR *)pplist);
3097 		efree((CHAR *)equivlist);
3098 		efree((CHAR *)buslist);
3099 		return;
3100 	}
3101 
3102 	if (namesamen(pt, x_("primitives"), l) == 0 && l >= 2)
3103 	{
3104 		/* list the primitive cell names */
3105 		ttyputmsg(_("----- Primitive Node Prototypes (%s) -----"), el_curtech->techname);
3106 		maxlen = 0;
3107 		for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3108 			maxlen = maxi(maxlen, estrlen(np->protoname));
3109 		maxlen += 2;  columns = MESSAGESWIDTH / maxlen;
3110 		total = 0;
3111 		for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3112 		{
3113 			if ((total % columns) == 0) (void)estrcpy(line, np->protoname); else
3114 				(void)estrcat(line, np->protoname);
3115 			if (np->nextnodeproto != NONODEPROTO && (total%columns) != columns-1)
3116 				for(i = estrlen(np->protoname); i < maxlen; i++)
3117 					(void)estrcat(line, x_(" "));
3118 			if ((total % columns) == columns-1) ttyputmsg(line);
3119 			total++;
3120 		}
3121 		if ((total % columns) != 0) ttyputmsg(line);
3122 		return;
3123 	}
3124 
3125 	if (namesamen(pt, x_("solvers"), l) == 0 && l >= 2)
3126 	{
3127 		ttyputmsg(_("Current constraint solver is %s (%s)"), el_curconstraint->conname,
3128 			TRANSLATE(el_curconstraint->condesc));
3129 		ttyputmsg(_("Other constraint solvers:"));
3130 		for(i=0; el_constraints[i].conname != 0; i++)
3131 		{
3132 			con = &el_constraints[i];
3133 			if (con == el_curconstraint) continue;
3134 			ttyputmsg(x_("  %s (%s)"), con->conname, TRANSLATE(con->condesc));
3135 		}
3136 		return;
3137 	}
3138 
3139 	if (namesamen(pt, x_("technologies"), l) == 0 && l >= 1)
3140 	{
3141 		ttyputmsg(_("Current technology is %s"), el_curtech->techname);
3142 		ttyputmsg(_("----- Technologies -----"));
3143 		for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
3144 			ttyputmsg(x_("%-9s %s"), tech->techname, tech->techdescript);
3145 		return;
3146 	}
3147 
3148 	if (namesamen(pt, x_("usage"), l) == 0 && l >= 1)
3149 	{
3150 		if (count <= 1)
3151 		{
3152 			ttyputusage(x_("show usage CELL"));
3153 			return;
3154 		}
3155 		np = getnodeproto(par[1]);
3156 		if (np == NONODEPROTO || np->primindex != 0)
3157 		{
3158 			us_abortcommand(_("'%s' is not a cell"), par[1]);
3159 			return;
3160 		}
3161 		if (np->firstinst == NONODEINST)
3162 		{
3163 			ttyputmsg(_("Cell %s is not used anywhere"), describenodeproto(np));
3164 			return;
3165 		}
3166 
3167 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3168 			for(wnp = olib->firstnodeproto; wnp != NONODEPROTO; wnp = wnp->nextnodeproto)
3169 				wnp->temp1 = 0;
3170 		for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
3171 			ni->parent->temp1++;
3172 		ttyputmsg(_("Cell %s is used in these locations:"), describenodeproto(np));
3173 		for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
3174 			for(wnp = olib->firstnodeproto; wnp != NONODEPROTO; wnp = wnp->nextnodeproto)
3175 				if (wnp->temp1 != 0)
3176 					ttyputmsg(_("  %ld %s in cell %s"), wnp->temp1,
3177 						makeplural(_("instance"), wnp->temp1), describenodeproto(wnp));
3178 		return;
3179 	}
3180 
3181 	if (namesamen(pt, x_("views"), l) == 0 && l >= 1)
3182 	{
3183 		if (count == 1)
3184 		{
3185 			ttyputmsg(_("Current views:"));
3186 			for(v = el_views; v != NOVIEW; v = v->nextview)
3187 				ttyputmsg(_("%s (short name %s)"), v->viewname, v->sviewname);
3188 			return;
3189 		}
3190 		np = getnodeproto(par[1]);
3191 		if (np == NONODEPROTO || np->primindex != 0)
3192 		{
3193 			us_abortcommand(_("'%s' is not a cell"), par[1]);
3194 			return;
3195 		}
3196 
3197 		infstr = initinfstr();
3198 		first = FALSE;
3199 		FOR_CELLGROUP(wnp, np)
3200 		{
3201 			if (first) addstringtoinfstr(infstr, x_(", "));
3202 			first = TRUE;
3203 			addstringtoinfstr(infstr, describenodeproto(wnp));
3204 		}
3205 		ttyputmsg(_("View contains: %s"), returninfstr(infstr));
3206 		return;
3207 	}
3208 	ttyputbadusage(x_("show"));
3209 }
3210 
us_size(INTBIG count,CHAR * par[])3211 void us_size(INTBIG count, CHAR *par[])
3212 {
3213 	REGISTER BOOLEAN serptrans, justnodes, justarcs, usetransformation, flipxy;
3214 	REGISTER INTBIG i, j, k, l, dxs, dys, lx, hx, ly, hy, dist, bestdist, otherx, othery,
3215 		rot, wid, dx, dy, fixedcorner, nc, ac, tot, edgealignment, *drot, *dtran, fun,
3216 		cursorbased, isin, otherin, nodecount, arccount, bits, lambda;
3217 	INTBIG offxl, offyl, offxh, offyh, truewid, rx, ry, orx, ory,
3218 		otheralign, xcur, ycur, xs, ys, *dlxs, *dlys, *dhxs, *dhys;
3219 	XARRAY trans;
3220 	REGISTER NODEINST *ni, *nodetosize, **nis;
3221 	REGISTER ARCINST *ai;
3222 	REGISTER NODEPROTO *np;
3223 	REGISTER CHAR *pp;
3224 	REGISTER GEOM **list, *geom;
3225 	REGISTER VARIABLE *var;
3226 	static POLYGON *poly = NOPOLYGON;
3227 	extern COMCOMP us_sizep, us_sizeyp, us_sizewp;
3228 
3229 	/* get polygon */
3230 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
3231 
3232 	/* get options */
3233 	cursorbased = 0;
3234 	justnodes = justarcs = FALSE;
3235 	l = 0;
3236 	pp = 0;
3237 	while (count > 0)
3238 	{
3239 		l = estrlen(pp = par[0]);
3240 		if (namesamen(pp, x_("corner-fixed"), l) == 0 && l >= 2)
3241 		{
3242 			cursorbased = 1;
3243 			count--;
3244 			par++;
3245 			continue;
3246 		}
3247 		if (namesamen(pp, x_("center-fixed"), l) == 0 && l >= 2)
3248 		{
3249 			cursorbased = 2;
3250 			count--;
3251 			par++;
3252 			continue;
3253 		}
3254 		if (namesamen(pp, x_("grab-point-fixed"), l) == 0)
3255 		{
3256 			us_abortcommand(_("Cannot size about the grab-point yet"));
3257 			return;
3258 		}
3259 		if (namesamen(pp, x_("nodes"), l) == 0)
3260 		{
3261 			justnodes = TRUE;
3262 			count--;
3263 			par++;
3264 			continue;
3265 		}
3266 		if (namesamen(pp, x_("arcs"), l) == 0)
3267 		{
3268 			justarcs = TRUE;
3269 			count--;
3270 			par++;
3271 			continue;
3272 		}
3273 		break;
3274 	}
3275 
3276 	nodetosize = NONODEINST;
3277 	list = us_gethighlighted(WANTARCINST|WANTNODEINST, 0, 0);
3278 	if (list[0] == NOGEOM)
3279 	{
3280 		us_abortcommand(_("First select nodes or arcs to resize"));
3281 		return;
3282 	}
3283 
3284 	/* disallow sizing if lock is on */
3285 	np = geomparent(list[0]);
3286 	if (us_cantedit(np, NONODEINST, TRUE)) return;
3287 
3288 	/* see how many are selected */
3289 	nodecount = arccount = 0;
3290 	for(i=0; list[i] != NOGEOM; i++)
3291 	{
3292 		if (list[i]->entryisnode)
3293 		{
3294 			nodecount++;
3295 			nodetosize = list[i]->entryaddr.ni;
3296 			if (!justarcs && nodetosize->proto->primindex == 0)
3297 			{
3298 				us_abortcommand(_("Cannot change cell size"));
3299 				return;
3300 			}
3301 		} else
3302 		{
3303 			arccount++;
3304 		}
3305 	}
3306 
3307 	/* see if a serpentine transistor is being scaled */
3308 	serptrans = FALSE;
3309 	if (nodecount == 1 && arccount == 0 && !justarcs)
3310 	{
3311 		if (us_cantedit(np, nodetosize, TRUE)) return;
3312 		if (nodetosize->proto->primindex != 0 && (nodetosize->proto->userbits&HOLDSTRACE) != 0)
3313 		{
3314 			fun = (nodetosize->proto->userbits&NFUNCTION) >> NFUNCTIONSH;
3315 			if (fun == NPTRANMOS || fun == NPTRADMOS || fun == NPTRAPMOS)
3316 			{
3317 				var = gettrace(nodetosize);
3318 				if (var != NOVARIABLE) serptrans = TRUE;
3319 			}
3320 		}
3321 	}
3322 
3323 	if (cursorbased != 0)
3324 	{
3325 		nc = nodecount;   ac = arccount;
3326 		if (justnodes) ac = 0;
3327 		if (justarcs) nc = 0;
3328 		if (nc + ac != 1)
3329 		{
3330 			us_abortcommand(_("Can only size one node or arc at a time"));
3331 			return;
3332 		}
3333 	}
3334 
3335 	if (count <= 0)
3336 	{
3337 		if ((nodecount > 1 || justnodes) && !justarcs)
3338 		{
3339 			if (serptrans)
3340 				count = ttygetparam(M_("Transistor width: "), &us_sizep, MAXPARS, par); else
3341 					count = ttygetparam(M_("X size: "), &us_sizep, MAXPARS, par);
3342 			if (count == 0)
3343 			{
3344 				us_abortedmsg();
3345 				return;
3346 			}
3347 			l = estrlen(pp = par[0]);
3348 		} else if ((arccount > 1 || justarcs) && !justnodes)
3349 		{
3350 			count = ttygetparam(M_("Width: "), &us_sizewp, MAXPARS, par);
3351 			if (count == 0)
3352 			{
3353 				us_abortedmsg();
3354 				return;
3355 			}
3356 			l = estrlen(pp = par[0]);
3357 		}
3358 	}
3359 
3360 	if ((nodecount != 0 || justnodes) && !justarcs)
3361 	{
3362 		if (cursorbased != 0)
3363 		{
3364 			if (serptrans)
3365 			{
3366 				us_abortcommand(_("No cursor scaling on serpentine transistors"));
3367 				ttyputmsg(_("Use explicit width instead"));
3368 				return;
3369 			}
3370 
3371 			/* save highlighting */
3372 			us_pushhighlight();
3373 			us_clearhighlightcount();
3374 
3375 			/* figure out the new size of the nodeinst */
3376 			nodesizeoffset(nodetosize, &offxl, &offyl, &offxh, &offyh);
3377 			lx = nodetosize->lowx+offxl;   hx = nodetosize->highx-offxh;
3378 			ly = nodetosize->lowy+offyl;   hy = nodetosize->highy-offyh;
3379 
3380 			if (cursorbased == 2)
3381 			{
3382 				/* center of node is fixed and all corners stretch */
3383 				if (us_demandxy(&xcur, &ycur)) return;
3384 				gridalign(&xcur, &ycur, 2, np);
3385 
3386 				/* adjust the cursor position if selecting interactively */
3387 				if ((us_tool->toolstate&INTERACTIVE) != 0)
3388 				{
3389 					us_sizeinit(nodetosize);
3390 					trackcursor(FALSE, us_ignoreup, us_nullvoid, us_sizecdown,
3391 						us_stopandpoponchar, us_dragup, TRACKDRAGGING);
3392 					if (el_pleasestop != 0) return;
3393 					if (us_demandxy(&xcur, &ycur)) return;
3394 					gridalign(&xcur, &ycur, 2, np);
3395 				}
3396 
3397 				/* transform cursor to account for node orientation */
3398 				makeangle((3600 - nodetosize->rotation)%3600, nodetosize->transpose, trans);
3399 				xform(xcur-(hx+lx)/2, ycur-(hy+ly)/2, &rx, &ry, trans);
3400 				xcur = (hx+lx)/2 + rx;
3401 				ycur = (hy+ly)/2 + ry;
3402 
3403 				/* compute new size of the nodeinst */
3404 				j = (hx+lx)/2;   i = abs(j - xcur);
3405 				lx = j-i;   hx = j+i;
3406 				j = (hy+ly)/2;   i = abs(j - ycur);
3407 				ly = j-i;   hy = j+i;
3408 				lx -= offxl;   hx += offxh;
3409 				ly -= offyl;   hy += offyh;
3410 			} else if (cursorbased == 1)
3411 			{
3412 				/* closest corner of node stretches to cursor */
3413 				/* adjust the cursor position if selecting interactively */
3414 				fixedcorner = -1;
3415 				if ((us_tool->toolstate&INTERACTIVE) != 0)
3416 				{
3417 					us_sizeinit(nodetosize);
3418 					trackcursor(TRUE, us_sizedown, us_nullvoid, us_sizedown,
3419 						us_stopandpoponchar, us_dragup, TRACKDRAGGING);
3420 					if (el_pleasestop != 0) return;
3421 					if (us_demandxy(&xcur, &ycur)) return;
3422 					gridalign(&xcur, &ycur, 1, np);
3423 					fixedcorner = us_sizeterm();
3424 				}
3425 				if (us_demandxy(&xcur, &ycur)) return;
3426 				gridalign(&xcur, &ycur, 1, np);
3427 				makerot(nodetosize, trans);
3428 
3429 				/* determine which corner is fixed */
3430 				if (fixedcorner < 0)
3431 				{
3432 					xform(lx, ly, &rx, &ry, trans);
3433 					bestdist = abs(rx - xcur) + abs(ry - ycur);
3434 					fixedcorner = 1;	/* lower-left */
3435 					xform(hx, ly, &rx, &ry, trans);
3436 					dist = abs(rx - xcur) + abs(ry - ycur);
3437 					if (dist < bestdist)
3438 					{
3439 						bestdist = dist;   fixedcorner = 2;	/* lower-right */
3440 					}
3441 					xform(lx, hy, &rx, &ry, trans);
3442 					dist = abs(rx - xcur) + abs(ry - ycur);
3443 					if (dist < bestdist)
3444 					{
3445 						bestdist = dist;   fixedcorner = 3;	/* upper-left */
3446 					}
3447 					xform(hx, hy, &rx, &ry, trans);
3448 					dist = abs(rx - xcur) + abs(ry - ycur);
3449 					if (dist < bestdist) fixedcorner = 4;	/* upper-right */
3450 				}
3451 
3452 				/* check the lower-left corner */
3453 				bits = getbuckybits();
3454 				switch (fixedcorner)
3455 				{
3456 					case 1:		/* lower-left */
3457 						otherx = hx;   othery = hy;
3458 						if ((bits&CONTROLDOWN) != 0)
3459 						{
3460 							xform(lx, ly, &orx, &ory, trans);
3461 							xform(xcur, ycur, &rx, &ry, trans);
3462 							if (abs(rx-orx) < abs(ry-ory)) xcur = lx; else
3463 								ycur = ly;
3464 						}
3465 						break;
3466 					case 2:		/* lower-right */
3467 						otherx = lx;   othery = hy;
3468 						if ((bits&CONTROLDOWN) != 0)
3469 						{
3470 							xform(hx, ly, &orx, &ory, trans);
3471 							xform(xcur, ycur, &rx, &ry, trans);
3472 							if (abs(rx-orx) < abs(ry-ory)) xcur = hx; else
3473 								ycur = ly;
3474 						}
3475 						break;
3476 					case 3:		/* upper-left */
3477 						otherx = hx;   othery = ly;
3478 						if ((bits&CONTROLDOWN) != 0)
3479 						{
3480 							xform(lx, hy, &orx, &ory, trans);
3481 							xform(xcur, ycur, &rx, &ry, trans);
3482 							if (abs(rx-orx) < abs(ry-ory)) xcur = lx; else
3483 								ycur = hy;
3484 						}
3485 						break;
3486 					case 4:		/* upper-right */
3487 						otherx = lx;   othery = ly;
3488 						if ((bits&CONTROLDOWN) != 0)
3489 						{
3490 							xform(hx, hy, &orx, &ory, trans);
3491 							xform(xcur, ycur, &rx, &ry, trans);
3492 							if (abs(rx-orx) < abs(ry-ory)) xcur = hx; else
3493 								ycur = hy;
3494 						}
3495 						break;
3496 					default:
3497 						otherx = othery = 0;
3498 				}
3499 
3500 				/* transform the cursor back through the node's orientation */
3501 				xform(otherx, othery, &rx, &ry, trans);
3502 				lx = mini(xcur, rx);
3503 				ly = mini(ycur, ry);
3504 				hx = maxi(xcur, rx);
3505 				hy = maxi(ycur, ry);
3506 
3507 				makeangle((3600 - nodetosize->rotation)%3600, nodetosize->transpose, trans);
3508 				xform(lx-(hx+lx)/2, ly-(hy+ly)/2, &rx, &ry, trans);
3509 				xform(hx-(hx+lx)/2, hy-(hy+ly)/2, &xs, &ys, trans);
3510 				rx += (hx+lx)/2;   ry += (hy+ly)/2;
3511 				xs += (hx+lx)/2;   ys += (hy+ly)/2;
3512 				lx = mini(xs, rx) - offxl;
3513 				ly = mini(ys, ry) - offyl;
3514 				hx = maxi(xs, rx) + offxh;
3515 				hy = maxi(ys, ry) + offyh;
3516 			} else
3517 			{
3518 				/* grab-point fixed and all corners stretch */
3519 				ttyputerr(_("Cannot do grab-point stretching yet"));
3520 				return;
3521 			}
3522 
3523 			/* make sure size is actually changing */
3524 			if (lx == nodetosize->lowx && ly == nodetosize->lowy && hx == nodetosize->highx &&
3525 				hy == nodetosize->highy)
3526 			{
3527 				ttyputverbose(M_("Null node scaling"));
3528 				us_pophighlight(FALSE);
3529 				return;
3530 			}
3531 
3532 			if ((nodetosize->proto->userbits&NSQUARE) != 0)
3533 			{
3534 				/* make sure the node is square */
3535 				xs = hx - lx;   ys = hy - ly;
3536 				if (xs != ys)
3537 				{
3538 					if (xs < ys)
3539 					{
3540 						lx = (lx + hx) / 2 - ys/2;   hx = lx + ys;
3541 					} else
3542 					{
3543 						ly = (ly + hy) / 2 - xs/2;   hy = ly + xs;
3544 					}
3545 				}
3546 			}
3547 
3548 			/* modify the node */
3549 			startobjectchange((INTBIG)nodetosize, VNODEINST);
3550 			us_scaletraceinfo(nodetosize, lx, hx, ly, hy);
3551 			modifynodeinst(nodetosize, lx-nodetosize->lowx, ly-nodetosize->lowy,
3552 				hx-nodetosize->highx, hy-nodetosize->highy, 0, 0);
3553 			endobjectchange((INTBIG)nodetosize, VNODEINST);
3554 
3555 			/* adjust text descriptors on sized invisible pins */
3556 			us_adjustdisplayabletext(nodetosize);
3557 
3558 			/* restore highlighting */
3559 			us_pophighlight(TRUE);
3560 		} else
3561 		{
3562 			/* handle serpentine transistors specially */
3563 			if (serptrans)
3564 			{
3565 				i = atofr(pp);
3566 				if (i <= 0)
3567 				{
3568 					us_abortcommand(_("Width must be positive"));
3569 					return;
3570 				}
3571 
3572 				/* save highlighting */
3573 				us_pushhighlight();
3574 				us_clearhighlightcount();
3575 
3576 				/* size the node */
3577 				startobjectchange((INTBIG)nodetosize, VNODEINST);
3578 				(void)setvalkey((INTBIG)nodetosize, VNODEINST, el_transistor_width_key, i, VFRACT);
3579 				endobjectchange((INTBIG)nodetosize, VNODEINST);
3580 
3581 				/* restore highlighting */
3582 				us_pophighlight(TRUE);
3583 				return;
3584 			}
3585 
3586 			/* get the new X size */
3587 			lambda = lambdaofnode(nodetosize);
3588 			i = atola(pp, lambda);
3589 			if (i&1) i++;
3590 			if (i < 0)
3591 			{
3592 				us_abortcommand(_("X size must be positive"));
3593 				return;
3594 			}
3595 
3596 			/* get the new Y size */
3597 			if (count <= 1)
3598 			{
3599 				if ((nodetosize->proto->userbits&NSQUARE) != 0) par[1] = pp; else
3600 				{
3601 					count = ttygetparam(_("Y size: "), &us_sizeyp, MAXPARS-1, &par[1]) + 1;
3602 					if (count == 1)
3603 					{
3604 						us_abortedmsg();
3605 						return;
3606 					}
3607 				}
3608 			}
3609 			j = atola(par[1], lambda);
3610 			if (j&1) j++;
3611 			if (j < 0)
3612 			{
3613 				us_abortcommand(_("Y size must not be negative"));
3614 				return;
3615 			}
3616 
3617 			/* see if transformations should be considered */
3618 			usetransformation = FALSE;
3619 			if (count > 2 && namesamen(par[2], x_("use-transformation"), l) == 0)
3620 				usetransformation = TRUE;
3621 
3622 			/* count the number of nodes that will be changed */
3623 			tot = 0;
3624 			for(k=0; list[k] != NOGEOM; k++)
3625 			{
3626 				geom = list[k];
3627 				if (!geom->entryisnode) continue;
3628 				nodetosize = geom->entryaddr.ni;
3629 				if (nodetosize->proto->primindex == 0) continue;
3630 				tot++;
3631 			}
3632 			if (tot <= 0)
3633 			{
3634 				ttyputmsg(_("No nodes changed"));
3635 				return;
3636 			}
3637 			nis = (NODEINST **)emalloc(tot * (sizeof (NODEINST *)), us_tool->cluster);
3638 			if (nis == 0) return;
3639 			dlxs = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3640 			if (dlxs == 0) return;
3641 			dlys = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3642 			if (dlys == 0) return;
3643 			dhxs = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3644 			if (dhxs == 0) return;
3645 			dhys = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3646 			if (dhys == 0) return;
3647 			drot = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3648 			if (drot == 0) return;
3649 			dtran = (INTBIG *)emalloc(tot * SIZEOFINTBIG, us_tool->cluster);
3650 			if (dtran == 0) return;
3651 
3652 			/* save highlighting */
3653 			us_pushhighlight();
3654 			us_clearhighlightcount();
3655 
3656 			tot = 0;
3657 			for(k=0; list[k] != NOGEOM; k++)
3658 			{
3659 				geom = list[k];
3660 				if (!geom->entryisnode) continue;
3661 				nodetosize = geom->entryaddr.ni;
3662 				if (nodetosize->proto->primindex == 0) continue;
3663 
3664 				/* see if X and Y size factors should be flipped */
3665 				flipxy = FALSE;
3666 				if (usetransformation)
3667 				{
3668 					rot = nodetosize->rotation;
3669 					if (nodetosize->transpose != 0) rot = (rot + 900) % 3600;
3670 					if (rot == 900 || rot == 2700) flipxy = TRUE;
3671 				}
3672 
3673 				nodesizeoffset(nodetosize, &offxl, &offyl, &offxh, &offyh);
3674 				if (flipxy)
3675 				{
3676 					if (pp[0] != 0) dy = i; else
3677 					{
3678 						dy = (nodetosize->highy - nodetosize->lowy) - offyl - offyh;
3679 					}
3680 					if (par[1][0] != 0) dx = j; else
3681 					{
3682 						dx = (nodetosize->highx - nodetosize->lowx) - offxl - offxh;
3683 					}
3684 				} else
3685 				{
3686 					if (pp[0] != 0) dx = i; else
3687 					{
3688 						dx = (nodetosize->highx - nodetosize->lowx) - offxl - offxh;
3689 					}
3690 					if (par[1][0] != 0) dy = j; else
3691 					{
3692 						dy = (nodetosize->highy - nodetosize->lowy) - offyl - offyh;
3693 					}
3694 				}
3695 				if ((nodetosize->proto->userbits&NSQUARE) != 0 && dx != dy)
3696 				{
3697 					dx = dy = maxi(dx, dy);
3698 					if (nodecount == 1 && arccount == 0)
3699 					{
3700 						lambda = lambdaofnode(nodetosize);
3701 						ttyputmsg(_("Warning: node must be square, making it %sx%s"),
3702 							latoa(dx, lambda), latoa(dy, lambda));
3703 					}
3704 				}
3705 				dxs = dx+offxl+offxh - (nodetosize->highx - nodetosize->lowx);
3706 				dys = dy+offyl+offyh - (nodetosize->highy - nodetosize->lowy);
3707 				if (dxs == 0 && dys == 0)
3708 				{
3709 					if (nodecount == 1 && arccount == 0)
3710 						ttyputverbose(M_("Null node scaling"));
3711 					continue;
3712 				}
3713 
3714 				nis[tot] = nodetosize;
3715 				dlxs[tot] = -dxs/2;
3716 				dlys[tot] = -dys/2;
3717 				dhxs[tot] = dxs/2;
3718 				dhys[tot] = dys/2;
3719 				drot[tot] = 0;
3720 				dtran[tot] = 0;
3721 				tot++;
3722 			}
3723 
3724 			/* size the nodes */
3725 			for(i=0; i<tot; i++)
3726 			{
3727 				nodetosize = nis[i];
3728 				startobjectchange((INTBIG)nodetosize, VNODEINST);
3729 				us_scaletraceinfo(nodetosize, nodetosize->lowx+dlxs[i],
3730 					nodetosize->highx+dhxs[i], nodetosize->lowy+dlys[i],
3731 						nodetosize->highy+dhys[i]);
3732 			}
3733 
3734 			/* modify all of the nodes at once */
3735 			modifynodeinsts(tot, nis, dlxs, dlys, dhxs, dhys, drot, dtran);
3736 
3737 			/* clean up change */
3738 			for(i=0; i<tot; i++)
3739 			{
3740 				nodetosize = nis[i];
3741 				endobjectchange((INTBIG)nodetosize, VNODEINST);
3742 
3743 				/* adjust text descriptors on sized invisible pins */
3744 				us_adjustdisplayabletext(nodetosize);
3745 			}
3746 
3747 			/* free memory */
3748 			efree((CHAR *)nis);
3749 			efree((CHAR *)dlxs);
3750 			efree((CHAR *)dlys);
3751 			efree((CHAR *)dhxs);
3752 			efree((CHAR *)dhys);
3753 			efree((CHAR *)drot);
3754 			efree((CHAR *)dtran);
3755 
3756 			/* solve constraints */
3757 			(*el_curconstraint->solve)(np);
3758 
3759 			/* restore highlighting */
3760 			us_pophighlight(TRUE);
3761 		}
3762 	} else if ((arccount != 0 || justarcs) && !justnodes)
3763 	{
3764 		if (cursorbased != 0 && (arccount != 1 || nodecount != 0))
3765 		{
3766 			us_abortcommand(_("Can only use cursor-based scaling on one arc"));
3767 			return;
3768 		}
3769 
3770 		/* save highlighting */
3771 		us_pushhighlight();
3772 		us_clearhighlightcount();
3773 
3774 		for(j=0; list[j] != NOGEOM; j++)
3775 		{
3776 			geom = list[j];
3777 			if (geom->entryisnode) continue;
3778 			ai = geom->entryaddr.ai;
3779 			ai->end[0].nodeinst->temp1 = 0;
3780 			ai->end[1].nodeinst->temp1 = 0;
3781 		}
3782 
3783 		for(j=0; list[j] != NOGEOM; j++)
3784 		{
3785 			geom = list[j];
3786 			if (geom->entryisnode) continue;
3787 			ai = geom->entryaddr.ai;
3788 			if (cursorbased != 0)
3789 			{
3790 				/* adjust the cursor position if selecting interactively */
3791 				if ((us_tool->toolstate&INTERACTIVE) != 0)
3792 				{
3793 					us_sizeainit(ai);
3794 					trackcursor(FALSE, us_ignoreup, us_sizeabegin, us_sizeadown,
3795 						us_stopandpoponchar, us_dragup, TRACKDRAGGING);
3796 					if (el_pleasestop != 0)
3797 					{
3798 						us_pophighlight(FALSE);
3799 						return;
3800 					}
3801 				}
3802 
3803 				/* get location of cursor */
3804 				if (us_demandxy(&xcur, &ycur))
3805 				{
3806 					us_pophighlight(FALSE);
3807 					return;
3808 				}
3809 				gridalign(&xcur, &ycur, 2, np);
3810 
3811 				/* figure out the new size of the arcinst (manhattan only) */
3812 				if (ai->end[0].xpos == ai->end[1].xpos)
3813 					wid = abs(xcur - ai->end[0].xpos) * 2; else
3814 						wid = abs(ycur - ai->end[0].ypos) * 2;
3815 			} else
3816 			{
3817 				lambda = lambdaofarc(ai);
3818 				wid = atola(pp, lambda);
3819 				if (wid&1) wid++;
3820 				if (wid < 0)
3821 				{
3822 					us_abortcommand(_("Width must not be negative"));
3823 					us_pophighlight(FALSE);
3824 					return;
3825 				}
3826 			}
3827 			truewid = arcwidthoffset(ai) + wid;
3828 			if (truewid == ai->width)
3829 			{
3830 				ttyputverbose(M_("Null arc scaling"));
3831 				continue;
3832 			}
3833 
3834 			/* handle edge alignment if possible */
3835 			dxs = dys = 0;
3836 			if (us_edgealignment_ratio != 0 && (ai->end[0].xpos == ai->end[1].xpos ||
3837 				ai->end[0].ypos == ai->end[1].ypos))
3838 			{
3839 				edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
3840 				if (ai->end[0].xpos == ai->end[1].xpos)
3841 				{
3842 					/* vertical arc */
3843 					otherx = us_alignvalue(ai->end[0].xpos + wid/2, edgealignment, &otheralign) -
3844 						wid/2;
3845 					otheralign -= wid/2;
3846 					isin = otherin = 0;
3847 					for(i=0; i<2; i++)
3848 					{
3849 						shapeportpoly(ai->end[i].nodeinst, ai->end[i].portarcinst->proto, poly, FALSE);
3850 						if (isinside(otherx, ai->end[i].ypos, poly)) isin++;
3851 						if (isinside(otheralign, ai->end[i].ypos, poly)) otherin++;
3852 					}
3853 					if (isin == 2) dxs = otherx - ai->end[0].xpos; else
3854 						if (otherin == 2) dxs = otheralign - ai->end[0].xpos;
3855 				}
3856 				if (ai->end[0].ypos == ai->end[1].ypos)
3857 				{
3858 					/* horizontal arc */
3859 					othery = us_alignvalue(ai->end[0].ypos + wid/2,
3860 						edgealignment, &otheralign) - wid/2;
3861 					otheralign -= wid/2;
3862 					isin = otherin = 0;
3863 					for(i=0; i<2; i++)
3864 					{
3865 						shapeportpoly(ai->end[i].nodeinst, ai->end[i].portarcinst->proto, poly, FALSE);
3866 						if (isinside(ai->end[i].xpos, othery, poly)) isin++;
3867 						if (isinside(ai->end[i].xpos, otheralign, poly)) otherin++;
3868 					}
3869 					if (isin == 2) dys = othery - ai->end[0].ypos; else
3870 						if (otherin == 2) dys = otheralign - ai->end[0].ypos;
3871 				}
3872 			}
3873 			startobjectchange((INTBIG)ai, VARCINST);
3874 			if (modifyarcinst(ai, truewid - ai->width, dxs, dys, dxs, dys))
3875 			{
3876 				lambda = lambdaofarc(ai);
3877 				ttyputerr(_("Cannot set arc width to %s"), latoa(truewid, lambda));
3878 			} else endobjectchange((INTBIG)ai, VARCINST);
3879 
3880 			/* scale the pins on either end */
3881 			if (dxs == 0 && dys == 0) for(i=0; i<2; i++)
3882 			{
3883 				/* get a node that hasn't been scaled already */
3884 				ni = ai->end[i].nodeinst;
3885 				if (ni->temp1 != 0) continue;
3886 				ni->temp1 = 1;
3887 
3888 				/* make sure it is a pin */
3889 				if (ni->proto->primindex == 0) continue;
3890 				if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPPIN) continue;
3891 
3892 				/* see if it is already large enough */
3893 				nodesizeoffset(ni, &offxl, &offyl, &offxh, &offyh);
3894 				lx = ni->lowx+offxl;   hx = ni->highx-offxh;
3895 				ly = ni->lowy+offyl;   hy = ni->highy-offyh;
3896 				if (hx - lx >= wid && hy - ly >= wid) continue;
3897 
3898 				/* increase its size */
3899 				if (hx - lx < wid) dx = (wid - (hx-lx)) / 2; else dx = 0;
3900 				if (hy - ly < wid) dy = (wid - (hy-ly)) / 2; else dy = 0;
3901 				startobjectchange((INTBIG)ni, VNODEINST);
3902 				modifynodeinst(ni, -dx, -dy, dx, dy, 0, 0);
3903 				endobjectchange((INTBIG)ni, VNODEINST);
3904 			}
3905 		}
3906 
3907 		/* restore highlighting */
3908 		us_pophighlight(TRUE);
3909 	}
3910 }
3911 
us_spread(INTBIG count,CHAR * par[])3912 void us_spread(INTBIG count, CHAR *par[])
3913 {
3914 	REGISTER NODEINST *ni;
3915 	REGISTER PORTARCINST *pi;
3916 	REGISTER GEOM **list;
3917 	CHAR *direction;
3918 	REGISTER INTBIG amount, i, lambda, moved, tot;
3919 	static POLYGON *poly = NOPOLYGON;
3920 
3921 	if (el_curconstraint != cla_constraint)
3922 	{
3923 		us_abortcommand(_("Must use the layout constraint system to spread"));
3924 		return;
3925 	}
3926 
3927 	/* get the nodeinst about which things must spread */
3928 	list = us_gethighlighted(WANTNODEINST, 0, 0);
3929 	if (list[0] == NOGEOM)
3930 	{
3931 		us_abortcommand(_("Must select nodes to spread"));
3932 		return;
3933 	}
3934 
3935 	/* get the direction of spread */
3936 	if (count == 0)
3937 	{
3938 		ttyputusage(x_("spread DIRECTION [AMOUNT]"));
3939 		return;
3940 	}
3941 	direction = par[0];
3942 	if (*direction != 'u' && *direction != 'd' &&
3943 		*direction != 'r' && *direction != 'l')
3944 	{
3945 		us_abortcommand(_("Direction must be 'left', 'right', 'up', or 'down'"));
3946 		return;
3947 	}
3948 
3949 	/* get the amount to spread */
3950 	if (count >= 2) amount = atola(par[1], 0); else
3951 	{
3952 		ni = list[0]->entryaddr.ni;
3953 		if (ni->proto->primindex != 0)
3954 		{
3955 			/* get polygon */
3956 			(void)needstaticpolygon(&poly, 4, us_tool->cluster);
3957 
3958 			/* get design-rule surround around this node as spread amount */
3959 			tot = nodepolys(ni, 0, NOWINDOWPART);   amount = 0;
3960 			for(i=0; i<tot; i++)
3961 			{
3962 				shapenodepoly(ni, i, poly);
3963 				amount = maxi(amount,
3964 					maxdrcsurround(ni->proto->tech, ni->parent->lib, poly->layer));
3965 			}
3966 
3967 			/* also count maximum width of arcs connected to this nodeinst */
3968 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3969 			{
3970 				if (pi->conarcinst == NOARCINST) continue;
3971 				amount = maxi(amount, pi->conarcinst->width);
3972 			}
3973 
3974 			/* if all else fails, spread by "lambda" */
3975 			lambda = lambdaofcell(ni->parent);
3976 			if (amount < lambda) amount = lambda;
3977 		} else
3978 		{
3979 			/* for cell, use cell size along spread axis */
3980 			if (*direction == 'l' || *direction == 'r') amount = ni->highx - ni->lowx; else
3981 				amount = ni->highy - ni->lowy;
3982 		}
3983 	}
3984 
3985 	/* save highlighting */
3986 	us_pushhighlight();
3987 	us_clearhighlightcount();
3988 
3989 	moved = 0;
3990 	for(i=0; list[i] != NOGEOM; i++)
3991 	{
3992 		ni = list[i]->entryaddr.ni;
3993 
3994 		/* disallow spreading if lock is on */
3995 		if (us_cantedit(ni->parent, NONODEINST, TRUE)) continue;
3996 
3997 		/* spread around the node */
3998 		moved += us_spreadaround(ni, amount, direction);
3999 	}
4000 	if (moved == 0) ttyputverbose(M_("Nothing changed"));
4001 
4002 	/* restore highlighting */
4003 	us_pophighlight(TRUE);
4004 }
4005 
us_system(INTBIG count,CHAR * par[])4006 void us_system(INTBIG count, CHAR *par[])
4007 {
4008 	REGISTER INTBIG l;
4009 	REGISTER CHAR *pt;
4010 
4011 	if (count == 0) l = estrlen(pt = x_("x")); else
4012 		l = estrlen(pt = par[0]);
4013 
4014 	if (namesamen(pt, x_("setstatusfont"), l) == 0 && l >= 1)
4015 	{
4016 		setmessagesfont();
4017 		return;
4018 	}
4019 #if defined(WIN32) || defined(USEQT)
4020 	if (namesamen(pt, x_("print"), l) == 0 && l >= 1)
4021 	{
4022 		printewindow();
4023 		return;
4024 	}
4025 	ttyputusage(x_("system print | setstatusfont"));
4026 #else
4027 	ttyputusage(x_("system setstatusfont"));
4028 #endif
4029 }
4030