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, ¥d)) 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