1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: conlingtt.c
6 * Linear inequality constraint system: graphics-to-text conversion
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 #include "global.h"
32 #include "conlin.h"
33
34 static WINDOWPART *cli_curwindow;
35
36 /* prototypes for local routines */
37 static void cli_addequivcon(ARCINST*);
38 static INTBIG cli_findtextconn(ARCINST*);
39 static CHAR *cli_makearcline(ARCINST*);
40 static CHAR *cli_makeportline(PORTPROTO*);
41 static BOOLEAN cli_uniquelayer(ARCINST*);
42 static INTBIG cli_addcomponentinfo(void*, NODEINST*);
43 static void cli_addcomponentdata(void*, COMPONENT*);
44 static CHAR *cli_componentname(NODEINST*);
45 static void cli_addcomponentline(CHAR*, WINDOWPART*);
46 static void cli_addattr(void*, ATTR*);
47 static void cli_addnodeprotoname(void*, NODEPROTO*);
48
49 /************************** IDENTIFY EQUIVALENT TEXT **************************/
50
51 /*
52 * routine to highlight the text that is equivalent to the graphic object "geom"
53 */
cli_highlightequivalent(GEOM * geom)54 void cli_highlightequivalent(GEOM *geom)
55 {
56 REGISTER NODEPROTO *par;
57 REGISTER ARCINST *ai;
58 REGISTER NODEINST *ni;
59 REGISTER INTBIG i, cindex, total;
60 REGISTER CHAR *str, *compname;
61 REGISTER COMPONENTDEC *dec;
62 REGISTER COMPONENT *compo;
63
64 par = geomparent(geom);
65 if (cli_curcell != par) return;
66
67 /* handle pointing to graphics */
68 if (!geom->entryisnode)
69 {
70 ai = geom->entryaddr.ai;
71 cindex = cli_findtextconn(ai);
72 if (cindex != -1) (void)asktool(us_tool, x_("edit-highlightline"), (INTBIG)cli_curwindow, cindex);
73 return;
74 }
75
76 /* highlight the equivalent node */
77 ni = geom->entryaddr.ni;
78 compname = cli_componentname(ni);
79 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
80 for(i=0; i<total; i++)
81 {
82 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
83 if (str == NOSTRING) break;
84 if (cli_linetype(str) != LINEDECL) continue;
85 dec = cli_parsecomp(str, FALSE);
86 if (dec == NOCOMPONENTDEC) continue;
87 if (ni->proto != getnodeproto(dec->protoname))
88 {
89 cli_deletecomponentdec(dec);
90 continue;
91 }
92
93 /* search for the changed node */
94 for(compo = dec->firstcomponent; compo != NOCOMPONENT; compo = compo->nextcomponent)
95 if (namesame(compname, compo->name) == 0) break;
96 if (compo != NOCOMPONENT) (void)asktool(us_tool, x_("edit-highlightline"), (INTBIG)cli_curwindow, i);
97 cli_deletecomponentdec(dec);
98 return;
99 }
100 }
101
102 /**************************** CONVERT ENTIRE CELL ****************************/
103
104 /*
105 * routine to fill the text window with the description of graphics cell "np".
106 * If "np" is NONODEPROTO, turn off the text system.
107 */
cli_maketextcell(NODEPROTO * np)108 void cli_maketextcell(NODEPROTO *np)
109 {
110 CHAR *name;
111 REGISTER CHAR *pt;
112 REGISTER NODEINST *ni, *oni;
113 REGISTER PORTPROTO *pp;
114 REGISTER ARCINST *ai;
115 REGISTER INTBIG first, lensofar, len, i, trunclen;
116 INTBIG chars, lines;
117 REGISTER void *infstr;
118
119 /* initialize the textual equivalent window */
120 cli_curcell = np;
121 if (!cli_texton)
122 {
123 (void)asktool(us_tool, x_("edit-describe"), (INTBIG)&name);
124 infstr = initinfstr();
125 addstringtoinfstr(infstr, name);
126 addstringtoinfstr(infstr, M_(" Editor equivalence for cell "));
127 addstringtoinfstr(infstr, np->protoname);
128 (void)allocstring(&name, returninfstr(infstr), el_tempcluster);
129 cli_curwindow = cli_makeeditorwindow(name, &chars, &lines);
130 efree(name);
131 if (cli_curwindow == NOWINDOWPART) return;
132 }
133 if (np == NONODEPROTO) return;
134
135 /* convert all components into declarations */
136 (void)asktool(us_tool, x_("edit-suspendgraphics"), (INTBIG)cli_curwindow);
137
138 /* erase the window */
139 len = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
140 for(i=0; i<len; i++)
141 (void)asktool(us_tool, x_("edit-deleteline"), (INTBIG)cli_curwindow, i);
142
143 /* load the cell */
144 trunclen = chars / 4 * 3;
145 cli_textlines = 0;
146 infstr = initinfstr();
147 addstringtoinfstr(infstr, x_("BEGINCELL "));
148 addstringtoinfstr(infstr, np->protoname);
149 addstringtoinfstr(infstr, x_(";"));
150 (void)asktool(us_tool, x_("edit-addline"), (INTBIG)cli_curwindow, 0, (INTBIG)returninfstr(infstr));
151 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
152 ni->temp1 = 0;
153 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
154 {
155 if (ni->temp1 != 0) continue;
156
157 /* gather all of the nodes of this type */
158 first = 0;
159 lensofar = 0;
160 for(oni = np->firstnodeinst; oni != NONODEINST; oni = oni->nextnodeinst)
161 {
162 if (oni->proto != ni->proto) continue;
163
164 /* try to keep the lines down to a reasonable length */
165 if (lensofar > trunclen)
166 {
167 addtoinfstr(infstr, ' ');
168 cli_addnodeprotoname(infstr, ni->proto);
169 addtoinfstr(infstr, ';');
170 cli_addcomponentline(returninfstr(infstr), cli_curwindow);
171 first = 0;
172 lensofar = 0;
173 }
174 if (first == 0)
175 {
176 infstr = initinfstr();
177 addstringtoinfstr(infstr, x_("declare "));
178 lensofar = 8;
179 first++;
180 } else
181 {
182 addstringtoinfstr(infstr, x_(", "));
183 lensofar += 2;
184 }
185 pt = cli_componentname(oni);
186 lensofar += estrlen(pt);
187 addstringtoinfstr(infstr, pt);
188 oni->temp1 = 1;
189
190 /* add in size/rotation/location if not default */
191 lensofar += cli_addcomponentinfo(infstr, oni);
192 }
193 if (first != 0)
194 {
195 addtoinfstr(infstr, ' ');
196 cli_addnodeprotoname(infstr, ni->proto);
197 addtoinfstr(infstr, ';');
198 cli_addcomponentline(returninfstr(infstr), cli_curwindow);
199 }
200 }
201
202 /* now generate the "export" declarations */
203 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
204 cli_addcomponentline(cli_makeportline(pp), cli_curwindow);
205
206 /* now convert the constaints */
207 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
208 cli_addequivcon(ai);
209 cli_replaceendcell(x_("ENDCELL;"), cli_curwindow);
210 (void)asktool(us_tool, x_("edit-resumegraphics"), (INTBIG)cli_curwindow);
211 }
212
213 /***************************** GRAPHIC CHANGES *****************************/
214
215 /*
216 * routine to update text when a new graphic node "ni" is created
217 */
cli_eq_newnode(NODEINST * ni)218 void cli_eq_newnode(NODEINST *ni)
219 {
220 REGISTER COMPONENTDEC *dec;
221 REGISTER COMPONENT *compo;
222 REGISTER CHAR *str;
223 REGISTER INTBIG i, total;
224 REGISTER void *infstr;
225
226 /* ignore changes generated by constraint results */
227 if (cli_ownchanges) return;
228
229 /* ignore changes made to a cell not being equated */
230 if (ni->parent != cli_curcell) return;
231
232 /* look for a declaration of this type of node */
233 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
234 for(i=0; i<total; i++)
235 {
236 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
237 if (str == NOSTRING) break;
238 if (cli_linetype(str) != LINEDECL) continue;
239 dec = cli_parsecomp(str, FALSE);
240 if (dec == NOCOMPONENTDEC) continue;
241 if (ni->proto != getnodeproto(dec->protoname))
242 {
243 cli_deletecomponentdec(dec);
244 continue;
245 }
246
247 /* found the declaration, rebuild with existing components */
248 infstr = initinfstr();
249 addstringtoinfstr(infstr, x_("declare "));
250 for(compo = dec->firstcomponent; compo != NOCOMPONENT; compo = compo->nextcomponent)
251 {
252 addstringtoinfstr(infstr, compo->name);
253 cli_addcomponentdata(infstr, compo);
254 addstringtoinfstr(infstr, x_(", "));
255 }
256
257 /* add in the new component */
258 addstringtoinfstr(infstr, cli_componentname(ni));
259 (void)cli_addcomponentinfo(infstr, ni);
260 addtoinfstr(infstr, ' ');
261
262 /* finish the declaration and replace the line */
263 addstringtoinfstr(infstr, dec->protoname);
264 addtoinfstr(infstr, ';');
265 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
266 cli_deletecomponentdec(dec);
267 return;
268 }
269
270 /* build a simple declaration for this node */
271 infstr = initinfstr();
272 addstringtoinfstr(infstr, x_("declare "));
273 addstringtoinfstr(infstr, cli_componentname(ni));
274 (void)cli_addcomponentinfo(infstr, ni);
275 addtoinfstr(infstr, ' ');
276 cli_addnodeprotoname(infstr, ni->proto);
277 addtoinfstr(infstr, ';');
278 cli_addcomponentline(returninfstr(infstr), cli_curwindow);
279 }
280
281 /*
282 * routine to update text when graphic node "ni" is deleted
283 */
cli_eq_killnode(NODEINST * ni)284 void cli_eq_killnode(NODEINST *ni)
285 {
286 REGISTER CHAR *str, *compname;
287 REGISTER INTBIG first, i, total;
288 REGISTER COMPONENTDEC *dec;
289 REGISTER COMPONENT *compo, *ocomp;
290 REGISTER void *infstr;
291
292 /* see if node is in graphics cell that has equivalent text */
293 if (cli_ownchanges) return;
294
295 /* ignore changes made to a cell not being equated */
296 if (ni->parent != cli_curcell) return;
297
298 /* look for a declaration of this type of node */
299 compname = cli_componentname(ni);
300 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
301 for(i=0; i<total; i++)
302 {
303 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
304 if (str == NOSTRING) break;
305 if (cli_linetype(str) != LINEDECL) continue;
306 dec = cli_parsecomp(str, FALSE);
307 if (dec == NOCOMPONENTDEC) continue;
308 if (ni->proto != getnodeproto(dec->protoname))
309 {
310 cli_deletecomponentdec(dec);
311 continue;
312 }
313
314 /* search for the deleted node */
315 for(compo = dec->firstcomponent; compo != NOCOMPONENT; compo = compo->nextcomponent)
316 if (namesame(compname, compo->name) == 0) break;
317 if (compo == NOCOMPONENT)
318 {
319 cli_deletecomponentdec(dec);
320 continue;
321 }
322
323 /* delete the line if there are only two keywords */
324 if (dec->count == 1 && namesame(dec->firstcomponent->name, compname) == 0)
325 {
326 /* line had only one keyword: delete the line */
327 (void)asktool(us_tool, x_("edit-deleteline"), (INTBIG)cli_curwindow, i);
328 cli_textlines--;
329 cli_deletecomponentdec(dec);
330 return;
331 }
332
333 /* rebuild line without the deleted component */
334 infstr = initinfstr();
335 addstringtoinfstr(infstr, x_("declare "));
336 first = 0;
337 for(ocomp = dec->firstcomponent; ocomp != NOCOMPONENT; ocomp = ocomp->nextcomponent)
338 {
339 if (compo == ocomp) continue;
340 if (first != 0) addstringtoinfstr(infstr, x_(", "));
341 first++;
342 addstringtoinfstr(infstr, ocomp->name);
343 cli_addcomponentdata(infstr, ocomp);
344 }
345 addtoinfstr(infstr, ' ');
346 addstringtoinfstr(infstr, dec->protoname);
347 addtoinfstr(infstr, ';');
348 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
349 cli_deletecomponentdec(dec);
350 return;
351 }
352 ttyputmsg(M_("Warning: cannot find node %s in text"), compname);
353 }
354
355 /* handle the change of node "ni" */
cli_eq_modnode(NODEINST * ni)356 void cli_eq_modnode(NODEINST *ni)
357 {
358 /* see if node is in graphics cell that has equivalent text */
359 if (cli_ownchanges) return;
360 if (ni->parent == cli_curcell) cli_changeequivcomp(ni);
361 }
362
363 /* handle the creation of new arc "ai" */
cli_eq_newarc(ARCINST * ai)364 void cli_eq_newarc(ARCINST *ai)
365 {
366 REGISTER INTBIG i, j;
367 REGISTER NODEINST *ni;
368 REGISTER PORTARCINST *pi;
369
370 /* see if arc is in graphics cell that has equivalent text */
371 if (cli_ownchanges) return;
372 if (ai->parent != cli_curcell) return;
373
374 cli_addequivcon(ai);
375
376 /* see if end nodes now have one connection */
377 for(i=0; i<2; i++)
378 {
379 ni = ai->end[i].nodeinst;
380 j = 0;
381 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst) j++;
382 if (j == 1) cli_changeequivcomp(ni);
383 }
384 }
385
386 /* handle the deletion of arc "ai" */
cli_eq_killarc(ARCINST * ai)387 void cli_eq_killarc(ARCINST *ai)
388 {
389 REGISTER NODEINST *ni;
390 REGISTER INTBIG i;
391
392 /* see if arc is in graphics cell that has equivalent text */
393 if (cli_ownchanges) return;
394 if (ai->parent != cli_curcell) return;
395
396 cli_deleteequivcon(ai);
397
398 /* see if formerly connecting nodes need redefinition */
399 for(i=0; i<2; i++)
400 {
401 ni = ai->end[i].nodeinst;
402 if (ni->firstportarcinst == NOPORTARCINST)
403 cli_changeequivcomp(ni);
404 }
405 }
406
407 /*
408 * routine to handle the change of graphic arc "ai" by making an equivalent
409 * change to the text
410 */
cli_eq_modarc(ARCINST * ai)411 void cli_eq_modarc(ARCINST *ai)
412 {
413 REGISTER CHAR *str;
414 REGISTER INTBIG cindex;
415
416 /* see if arc is in graphics cell that has equivalent text */
417 if (cli_ownchanges) return;
418
419 /* ignore changes made to a cell not being equated */
420 if (ai->parent != cli_curcell) return;
421
422 /* get the text node that describes this arc */
423 cindex = cli_findtextconn(ai);
424 if (cindex == -1)
425 {
426 ttyputerr(M_("Cannot find text equivalent for arc %s"), describearcinst(ai));
427 return;
428 }
429
430 /* build the constraint message */
431 str = cli_makearcline(ai);
432
433 /* change the line */
434 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, cindex, (INTBIG)str);
435 }
436
437 /* handle the creation of port "pp" */
cli_eq_newport(PORTPROTO * pp)438 void cli_eq_newport(PORTPROTO *pp)
439 {
440 /* see if port is in graphics cell that has equivalent text */
441 if (cli_ownchanges) return;
442 if (pp->parent != cli_curcell) return;
443 cli_addcomponentline(cli_makeportline(pp), cli_curwindow);
444 }
445
446 /* handle the deletion of port "pp" */
cli_eq_killport(PORTPROTO * pp)447 void cli_eq_killport(PORTPROTO *pp)
448 {
449 REGISTER INTBIG i, total;
450 REGISTER CHAR *str;
451 REGISTER EXPORT *e;
452
453 /* see if port is in graphics cell that has equivalent text */
454 if (cli_ownchanges) return;
455 if (pp->parent != cli_curcell) return;
456
457 /* find the export line with this port */
458 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
459 for(i=0; i<total; i++)
460 {
461 /* get a line of text */
462 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
463 if (str == NOSTRING) break;
464 if (cli_linetype(str) != LINEEXPORT) continue;
465
466 /* see if export line is this one */
467 e = cli_parseexport(str, FALSE);
468 if (e == NOEXPORT) continue;
469 if (namesame(pp->protoname, e->portname) != 0)
470 {
471 cli_deleteexport(e);
472 continue;
473 }
474
475 /* export line found: delete it */
476 (void)asktool(us_tool, x_("edit-deleteline"), (INTBIG)cli_curwindow, i);
477 cli_textlines--;
478 cli_deleteexport(e);
479 break;
480 }
481 }
482
483 /* handle the modification of port "pp" */
cli_eq_modport(PORTPROTO * pp)484 void cli_eq_modport(PORTPROTO *pp)
485 {
486 REGISTER CHAR *str;
487 REGISTER EXPORT *e;
488 REGISTER INTBIG i, total;
489
490 /* see if port is in graphics cell that has equivalent text */
491 if (cli_ownchanges) return;
492 if (pp->parent != cli_curcell) return;
493
494 /* find the export line with this port */
495 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
496 for(i=0; i<total; i++)
497 {
498 /* get a line of text */
499 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
500 if (str == NOSTRING) break;
501 if (cli_linetype(str) != LINEEXPORT) continue;
502
503 /* see if export line is this one */
504 e = cli_parseexport(str, FALSE);
505 if (e == NOEXPORT) continue;
506 if (namesame(pp->protoname, e->portname) != 0)
507 {
508 cli_deleteexport(e);
509 continue;
510 }
511
512 /* export line found: rewrite it */
513 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i,
514 (INTBIG)cli_makeportline(pp));
515 cli_deleteexport(e);
516 break;
517 }
518 }
519
520 /* handle the creation of variable type "type", name "key", and value "addr" */
cli_eq_newvar(INTBIG addr,INTBIG type,INTBIG key)521 void cli_eq_newvar(INTBIG addr, INTBIG type, INTBIG key)
522 {
523 REGISTER NODEINST *ni;
524 CHAR line[50];
525 REGISTER VARIABLE *var;
526
527 if (cli_ownchanges) return;
528
529 if (type == VNODEINST)
530 {
531 /* node added variable: see if this is in a graphics cell */
532 ni = (NODEINST *)addr;
533 if (ni->parent != cli_curcell) return;
534
535 /* name changes are handled specially */
536 if (key == el_node_name_key)
537 {
538 /* construct the original name */
539 (void)esnprintf(line, 50, M_("NODE%ld"), (INTBIG)ni);
540
541 /* get the new node name */
542 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
543 if (var == NOVARIABLE) return;
544 cli_replacename(line, (CHAR *)var->addr);
545 return;
546 }
547
548 /* update the declaration */
549 cli_changeequivcomp(ni);
550 return;
551 }
552
553 if (type == VPORTPROTO)
554 {
555 cli_eq_modport((PORTPROTO *)addr);
556 return;
557 }
558
559 if (type == VARCINST)
560 {
561 cli_eq_modarc((ARCINST *)addr);
562 return;
563 }
564 }
565
566 /* handle the deletion of variable type "type", name "key", and value "addr" */
cli_eq_killvar(INTBIG addr,INTBIG type,INTBIG key)567 void cli_eq_killvar(INTBIG addr, INTBIG type, INTBIG key)
568 {
569 CHAR line[50];
570 REGISTER VARIABLE *var;
571 REGISTER NODEINST *ni;
572
573 if (cli_ownchanges) return;
574 if (type == VNODEINST)
575 {
576 /* node variable removed: see if this is in a graphics cell */
577 ni = (NODEINST *)addr;
578 if (ni->parent != cli_curcell) return;
579
580 if (key == el_node_name_key)
581 {
582 /* get the former name */
583 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
584 if (var == NOVARIABLE) return;
585
586 /* construct the new node name */
587 (void)esnprintf(line, 50, M_("NODE%ld"), (INTBIG)ni);
588 cli_replacename((CHAR *)var->addr, line);
589 return;
590 }
591
592 /* update the declaration */
593 cli_changeequivcomp(ni);
594 return;
595 }
596
597 if (type == VPORTPROTO)
598 {
599 cli_eq_modport((PORTPROTO *)addr);
600 return;
601 }
602
603 if (type == VARCINST)
604 {
605 cli_eq_modarc((ARCINST *)addr);
606 return;
607 }
608 }
609
cli_eq_solve(void)610 void cli_eq_solve(void)
611 {
612 cli_ownchanges = FALSE;
613 }
614
615 /***************************** HELPER ROUTINES *****************************/
616
617 /*
618 * routine to handle the addition of the text associated with new layout arc "ai"
619 */
cli_addequivcon(ARCINST * ai)620 void cli_addequivcon(ARCINST *ai)
621 {
622 REGISTER INTBIG i, total;
623
624 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
625
626 /* search for the last line with a valid connection declaration */
627 for(i = total-1; i >= 0; i--)
628 if (cli_linetype((CHAR *)asktool(us_tool, x_("edit-getline"),
629 (INTBIG)cli_curwindow, i)) == LINECONN) break;
630 if (i < 0)
631 {
632 /* no "connect" lines, take last line anywhere */
633 i = total-1;
634 }
635 (void)asktool(us_tool, x_("edit-addline"), (INTBIG)cli_curwindow, i+1, (INTBIG)cli_makearcline(ai));
636 cli_textlines++;
637 }
638
639 /*
640 * routine to handle the deletion of the text associated with layout arc "ai"
641 */
cli_deleteequivcon(ARCINST * ai)642 void cli_deleteequivcon(ARCINST *ai)
643 {
644 REGISTER INTBIG cindex;
645
646 /* get the text node that describes this arc */
647 cindex = cli_findtextconn(ai);
648 if (cindex != -1)
649 {
650 (void)asktool(us_tool, x_("edit-deleteline"), (INTBIG)cli_curwindow, cindex);
651 cli_textlines--;
652 }
653 }
654
655 /*
656 * routine to update the text information about of node "ni"
657 */
cli_changeequivcomp(NODEINST * ni)658 void cli_changeequivcomp(NODEINST *ni)
659 {
660 REGISTER CHAR *str, *compname;
661 REGISTER INTBIG i, total;
662 REGISTER COMPONENTDEC *dec;
663 REGISTER COMPONENT *compo, *ocomp;
664 REGISTER void *infstr;
665
666 /* look for a declaration of this type of node */
667 compname = cli_componentname(ni);
668 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
669 for(i=0; i<total; i++)
670 {
671 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
672 if (str == NOSTRING) break;
673 if (cli_linetype(str) != LINEDECL) continue;
674 dec = cli_parsecomp(str, FALSE);
675 if (dec == NOCOMPONENTDEC) continue;
676 if (ni->proto != getnodeproto(dec->protoname))
677 {
678 cli_deletecomponentdec(dec);
679 continue;
680 }
681
682 /* search for the changed node */
683 for(compo = dec->firstcomponent; compo != NOCOMPONENT; compo = compo->nextcomponent)
684 if (namesame(compname, compo->name) == 0) break;
685 if (compo == NOCOMPONENT)
686 {
687 cli_deletecomponentdec(dec);
688 continue;
689 }
690
691 infstr = initinfstr();
692 addstringtoinfstr(infstr, x_("declare "));
693 for(ocomp = dec->firstcomponent; ocomp != NOCOMPONENT; ocomp = ocomp->nextcomponent)
694 {
695 if (ocomp != dec->firstcomponent) addstringtoinfstr(infstr, x_(", "));
696 if (compo == ocomp)
697 {
698 addstringtoinfstr(infstr, cli_componentname(ni));
699 (void)cli_addcomponentinfo(infstr, ni);
700 } else
701 {
702 addstringtoinfstr(infstr, ocomp->name);
703 cli_addcomponentdata(infstr, ocomp);
704 }
705 }
706 addtoinfstr(infstr, ' ');
707 addstringtoinfstr(infstr, dec->protoname);
708 addtoinfstr(infstr, ';');
709 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
710 cli_deletecomponentdec(dec);
711 return;
712 }
713 ttyputmsg(M_("Warning: cannot find node %s in text"), compname);
714 }
715
716 /*
717 * routine to replace the name of graphics node "oni" (which used to be called
718 * "oldname") with the name "newname"
719 */
cli_replacename(CHAR * oldname,CHAR * newname)720 void cli_replacename(CHAR *oldname, CHAR *newname)
721 {
722 REGISTER CHAR *str;
723 REGISTER INTBIG i, rewrite, total;
724 CHAR line[50];
725 REGISTER EXPORT *e;
726 REGISTER COMPONENTDEC *dcl;
727 REGISTER COMPONENT *compo, *ocomp;
728 REGISTER CONNECTION *dec;
729 REGISTER CONS *cons;
730 REGISTER ATTR *a;
731 REGISTER void *infstr;
732
733 /* look through all statements for the old name */
734 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
735 for(i=0; i<total; i++)
736 {
737 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
738 if (str == NOSTRING) break;
739
740 /* search declaration statement */
741 if (cli_linetype(str) == LINEDECL)
742 {
743 dcl = cli_parsecomp(str, FALSE);
744 if (dcl == NOCOMPONENTDEC) continue;
745 for(compo = dcl->firstcomponent; compo != NOCOMPONENT; compo = compo->nextcomponent)
746 if (namesame(oldname, compo->name) == 0) break;
747 if (compo == NOCOMPONENT)
748 {
749 cli_deletecomponentdec(dcl);
750 continue;
751 }
752
753 /* rewrite the component declaration line */
754 infstr = initinfstr();
755 addstringtoinfstr(infstr, x_("declare "));
756 for(ocomp = dcl->firstcomponent; ocomp != NOCOMPONENT; ocomp = ocomp->nextcomponent)
757 {
758 if (ocomp != dcl->firstcomponent) addstringtoinfstr(infstr, x_(", "));
759 if (ocomp == compo) addstringtoinfstr(infstr, newname); else
760 addstringtoinfstr(infstr, ocomp->name);
761 cli_addcomponentdata(infstr, ocomp);
762 }
763 addtoinfstr(infstr, ' ');
764 addstringtoinfstr(infstr, dcl->protoname);
765 addtoinfstr(infstr, ';');
766 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
767 cli_deletecomponentdec(dcl);
768 continue;
769 }
770
771 /* search export statement */
772 if (cli_linetype(str) == LINEEXPORT)
773 {
774 e = cli_parseexport(str, FALSE);
775 if (e == NOEXPORT) continue;
776 if (namesame(e->component, oldname) != 0)
777 {
778 cli_deleteexport(e);
779 continue;
780 }
781
782 /* rewrite the export line */
783 infstr = initinfstr();
784 addstringtoinfstr(infstr, x_("export "));
785 if ((e->flag&(EXPCHAR|EXPATTR)) != 0)
786 {
787 if ((e->flag&EXPCHAR) != 0)
788 {
789 addstringtoinfstr(infstr, x_("[type="));
790 switch (e->bits&STATEBITS)
791 {
792 case INPORT :
793 addstringtoinfstr(infstr, M_("input")); break;
794 case OUTPORT:
795 addstringtoinfstr(infstr, M_("output")); break;
796 case BIDIRPORT:
797 addstringtoinfstr(infstr, M_("bidirectional")); break;
798 case PWRPORT:
799 addstringtoinfstr(infstr, M_("power")); break;
800 case GNDPORT:
801 addstringtoinfstr(infstr, M_("ground")); break;
802 case CLKPORT:
803 addstringtoinfstr(infstr, M_("clock")); break;
804 case C1PORT:
805 addstringtoinfstr(infstr, M_("clock1")); break;
806 case C2PORT:
807 addstringtoinfstr(infstr, M_("clock2")); break;
808 case C3PORT:
809 addstringtoinfstr(infstr, M_("clock3")); break;
810 case C4PORT:
811 addstringtoinfstr(infstr, M_("clock4")); break;
812 case C5PORT:
813 addstringtoinfstr(infstr, M_("clock5")); break;
814 case C6PORT:
815 addstringtoinfstr(infstr, M_("clock6")); break;
816 case REFOUTPORT:
817 addstringtoinfstr(infstr, M_("refout")); break;
818 case REFINPORT:
819 addstringtoinfstr(infstr, M_("refin")); break;
820 case REFBASEPORT:
821 addstringtoinfstr(infstr, M_("refbase")); break;
822 }
823 }
824 if ((e->flag&EXPATTR) != 0)
825 {
826 if ((e->flag&EXPCHAR) == 0) addtoinfstr(infstr, '['); else
827 addtoinfstr(infstr, ',');
828 for(a = e->firstattr; a != NOATTR; a = a->nextattr)
829 {
830 if (a != e->firstattr) addtoinfstr(infstr, ',');
831 cli_addattr(infstr, a);
832 }
833 }
834 addstringtoinfstr(infstr, x_("] "));
835 }
836 addstringtoinfstr(infstr, e->portname);
837 addstringtoinfstr(infstr, x_(" is "));
838 addstringtoinfstr(infstr, newname);
839 if (e->subport != 0)
840 {
841 addtoinfstr(infstr, ':');
842 addstringtoinfstr(infstr, e->subport);
843 }
844 addtoinfstr(infstr, ';');
845 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
846 cli_deleteexport(e);
847 continue;
848 }
849
850 /* search connection statement */
851 if (cli_linetype(str) == LINECONN)
852 {
853 dec = cli_parseconn(str, FALSE);
854 if (dec == NOCONNECTION) continue;
855
856 /* see if the connection line needs to be rewriten */
857 rewrite = 0;
858 if ((dec->flag&END1VALID) != 0 && namesame(dec->end1, oldname) == 0)
859 {
860 (void)reallocstring(&dec->end1, newname, el_tempcluster);
861 rewrite++;
862 }
863 if ((dec->flag&END2VALID) != 0 && namesame(dec->end2, oldname) == 0)
864 {
865 (void)reallocstring(&dec->end2, newname, el_tempcluster);
866 rewrite++;
867 }
868 if (rewrite == 0)
869 {
870 cli_deleteconnection(dec);
871 continue;
872 }
873
874 /* rewrite the connetion line */
875 infstr = initinfstr();
876 addstringtoinfstr(infstr, x_("connect "));
877 if ((dec->flag&(LAYERVALID|WIDTHVALID|ATTRVALID)) != 0)
878 {
879 if ((dec->flag&LAYERVALID) != 0)
880 {
881 addstringtoinfstr(infstr, x_("[layer="));
882 addstringtoinfstr(infstr, dec->layer);
883 }
884 if ((dec->flag&WIDTHVALID) != 0)
885 {
886 if ((dec->flag&LAYERVALID) != 0) addtoinfstr(infstr, ','); else
887 addtoinfstr(infstr, '[');
888 (void)esnprintf(line, 50, x_("width=%s"), latoa(dec->width, 0));
889 addstringtoinfstr(infstr, line);
890 }
891 if ((dec->flag&ATTRVALID) != 0)
892 {
893 if ((dec->flag&(LAYERVALID|WIDTHVALID)) != 0) addtoinfstr(infstr, ','); else
894 addtoinfstr(infstr, '[');
895 for(a = dec->firstattr; a != NOATTR; a = a->nextattr)
896 {
897 if (a != dec->firstattr) addtoinfstr(infstr, ',');
898 cli_addattr(infstr, a);
899 }
900 }
901 addstringtoinfstr(infstr, x_("] "));
902 }
903
904 addstringtoinfstr(infstr, dec->end1);
905 if ((dec->flag&PORT1VALID) != 0)
906 {
907 addtoinfstr(infstr, ':');
908 addstringtoinfstr(infstr, dec->port1);
909 }
910
911 for(cons = dec->firstcons; cons != NOCONS; cons = cons->nextcons)
912 {
913 addtoinfstr(infstr, ' ');
914 addstringtoinfstr(infstr, cons->direction);
915 addtoinfstr(infstr, ' ');
916 addstringtoinfstr(infstr, frtoa(cons->amount));
917 if (cons->flag == 1) addstringtoinfstr(infstr, x_(" or more"));
918 if (cons->flag == -1) addstringtoinfstr(infstr, x_(" or less"));
919 }
920
921 /* decide whether to print the arc offset */
922 if ((dec->flag&OFFSETVALID) != 0)
923 {
924 (void)esnprintf(line, 50, x_(" [%s,%s]"), latoa(dec->xoff, 0), latoa(dec->yoff, 0));
925 addstringtoinfstr(infstr, line);
926 }
927 addstringtoinfstr(infstr, x_(" to "));
928 addstringtoinfstr(infstr, dec->end2);
929 if ((dec->flag&PORT2VALID) != 0)
930 {
931 addtoinfstr(infstr, ':');
932 addstringtoinfstr(infstr, dec->port2);
933 }
934 addstringtoinfstr(infstr, x_(";"));
935 (void)asktool(us_tool, x_("edit-replaceline"), (INTBIG)cli_curwindow, i, (INTBIG)returninfstr(infstr));
936 cli_deleteconnection(dec);
937 }
938 }
939 }
940
941 /***************************** UTILITIES *****************************/
942
943 /*
944 * routine to find the text line associated with arc "ai". Returns the line
945 * index (-1 if it cannot be found).
946 */
cli_findtextconn(ARCINST * ai)947 INTBIG cli_findtextconn(ARCINST *ai)
948 {
949 REGISTER INTBIG i, total;
950 REGISTER CHAR *str;
951 REGISTER CONNECTION *dec;
952
953 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)cli_curwindow);
954 for(i=0; i<total; i++)
955 {
956 /* get a valid connection line */
957 str = (CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)cli_curwindow, i);
958 if (str == NOSTRING) break;
959 if (cli_linetype(str) != LINECONN) continue;
960 dec = cli_parseconn(str, TRUE);
961 if (dec == NOCONNECTION) continue;
962
963 /* must have both ends specified */
964 if ((dec->flag&(END1VALID|END2VALID)) != (END1VALID|END2VALID))
965 {
966 cli_deleteconnection(dec);
967 continue;
968 }
969
970 /* end nodes must be correct */
971 if (namesame(dec->end1, cli_componentname(ai->end[0].nodeinst)) != 0 ||
972 namesame(dec->end2, cli_componentname(ai->end[1].nodeinst)) != 0)
973 {
974 cli_deleteconnection(dec);
975 continue;
976 }
977
978 /* specified ports must be correct */
979 if ((dec->flag&PORT1VALID) != 0 &&
980 namesame(dec->port1, ai->end[0].portarcinst->proto->protoname) != 0)
981 {
982 cli_deleteconnection(dec);
983 continue;
984 }
985 if ((dec->flag&PORT2VALID) != 0 &&
986 namesame(dec->port2, ai->end[1].portarcinst->proto->protoname) != 0)
987 {
988 cli_deleteconnection(dec);
989 continue;
990 }
991
992 /* line of text found */
993 cli_deleteconnection(dec);
994 return(i);
995 }
996 return(-1);
997 }
998
999 /*
1000 * routine to convert an arc into a line of text with all constraints
1001 */
cli_makearcline(ARCINST * ai)1002 CHAR *cli_makearcline(ARCINST *ai)
1003 {
1004 CHAR line[50];
1005 REGISTER VARIABLE *var;
1006 REGISTER INTBIG i, len;
1007 REGISTER BOOLEAN doit, added;
1008 REGISTER INTBIG conx, cony, xcons, ycons, lambda;
1009 REGISTER LINCON *conptr;
1010 REGISTER void *infstr;
1011
1012 infstr = initinfstr();
1013 addstringtoinfstr(infstr, x_("connect "));
1014 added = FALSE;
1015 if (!cli_uniquelayer(ai))
1016 {
1017 addstringtoinfstr(infstr, x_("[layer="));
1018 addstringtoinfstr(infstr, describearcproto(ai->proto));
1019 added = TRUE;
1020 }
1021 if (ai->width != ai->proto->nominalwidth)
1022 {
1023 if (!added) addtoinfstr(infstr, '['); else addtoinfstr(infstr, ',');
1024 addstringtoinfstr(infstr, x_("width="));
1025 addstringtoinfstr(infstr, latoa(ai->width, 0));
1026 added = TRUE;
1027 }
1028 if (ai->numvar != 0) for(i=0; i<ai->numvar; i++)
1029 {
1030 var = &ai->firstvar[i];
1031 if ((var->type&VISARRAY) != 0) continue;
1032 if (!added) addtoinfstr(infstr, '['); else addtoinfstr(infstr, ',');
1033 addstringtoinfstr(infstr, (CHAR *)var->key);
1034 addtoinfstr(infstr, '=');
1035 addstringtoinfstr(infstr, describevariable(var, -1, 1));
1036 added = TRUE;
1037 }
1038 if (added) addstringtoinfstr(infstr, x_("] "));
1039 addstringtoinfstr(infstr, cli_componentname(ai->end[0].nodeinst));
1040 if (!cli_uniqueport(ai->end[0].nodeinst, ai->end[0].portarcinst->proto))
1041 {
1042 addtoinfstr(infstr, ':');
1043 addstringtoinfstr(infstr, ai->end[0].portarcinst->proto->protoname);
1044 }
1045 var = getvalkey((INTBIG)ai, VARCINST, VINTEGER|VISARRAY, cli_properties_key);
1046
1047 /* initialize the X constraint to be different from the actual arc size */
1048 xcons = ycons = 0;
1049 conx = cony = 0;
1050 if (var != NOVARIABLE)
1051 {
1052 len = getlength(var) / LINCONSIZE;
1053 lambda = lambdaofarc(ai);
1054 for(i=0; i<len; i++)
1055 {
1056 conptr = &((LINCON *)var->addr)[i];
1057
1058 switch (conptr->variable)
1059 {
1060 case CLLEFT:
1061 xcons++;
1062 conx = -conptr->value * lambda / WHOLE;
1063 (void)esnprintf(line, 50, _(" left %s"), latoa(-conx, 0));
1064 break;
1065 case CLRIGHT:
1066 xcons++;
1067 conx = conptr->value * lambda / WHOLE;
1068 (void)esnprintf(line, 50, x_(" right %s"), latoa(conx, 0));
1069 break;
1070 case CLDOWN:
1071 ycons++;
1072 cony = -conptr->value * lambda / WHOLE;
1073 (void)esnprintf(line, 50, x_(" down %s"), latoa(-cony, 0));
1074 break;
1075 case CLUP:
1076 ycons++;
1077 cony = conptr->value * lambda / WHOLE;
1078 (void)esnprintf(line, 50, x_(" up %s"), latoa(cony, 0));
1079 break;
1080 }
1081 addstringtoinfstr(infstr, line);
1082 if (conptr->oper == 0) addstringtoinfstr(infstr, x_(" or more"));
1083 if (conptr->oper == 2) addstringtoinfstr(infstr, x_(" or less"));
1084 }
1085 }
1086
1087 /* decide whether to print the arc offset */
1088 doit = FALSE;
1089 if (xcons > 1 || ycons > 1) doit = TRUE;
1090 if (xcons == 0 && ycons == 0) doit = TRUE;
1091 if (conx != ai->end[1].xpos - ai->end[0].xpos || cony != ai->end[1].ypos - ai->end[0].ypos)
1092 doit = TRUE;
1093 if (doit)
1094 {
1095 (void)esnprintf(line, 50, x_(" [%s,%s]"), latoa(ai->end[1].xpos - ai->end[0].xpos, 0),
1096 latoa(ai->end[1].ypos - ai->end[0].ypos, 0));
1097 addstringtoinfstr(infstr, line);
1098 }
1099 addstringtoinfstr(infstr, x_(" to "));
1100 addstringtoinfstr(infstr, cli_componentname(ai->end[1].nodeinst));
1101 if (!cli_uniqueport(ai->end[1].nodeinst, ai->end[1].portarcinst->proto))
1102 {
1103 addtoinfstr(infstr, ':');
1104 addstringtoinfstr(infstr, ai->end[1].portarcinst->proto->protoname);
1105 }
1106 addstringtoinfstr(infstr, x_(";"));
1107 return(returninfstr(infstr));
1108 }
1109
1110 /*
1111 * routine to handle the addition of the text associated with new port "pp"
1112 */
cli_makeportline(PORTPROTO * pp)1113 CHAR *cli_makeportline(PORTPROTO *pp)
1114 {
1115 REGISTER BOOLEAN added;
1116 REGISTER INTBIG i;
1117 REGISTER VARIABLE *var;
1118 REGISTER void *infstr;
1119
1120 infstr = initinfstr();
1121 addstringtoinfstr(infstr, x_("export "));
1122 if ((pp->userbits&STATEBITS) != 0)
1123 {
1124 addstringtoinfstr(infstr, x_("[type="));
1125 switch (pp->userbits&STATEBITS)
1126 {
1127 case INPORT: addstringtoinfstr(infstr, x_("input")); break;
1128 case OUTPORT: addstringtoinfstr(infstr, x_("output")); break;
1129 case BIDIRPORT: addstringtoinfstr(infstr, x_("bidirectional")); break;
1130 case PWRPORT: addstringtoinfstr(infstr, x_("power")); break;
1131 case GNDPORT: addstringtoinfstr(infstr, x_("ground")); break;
1132 case CLKPORT: addstringtoinfstr(infstr, x_("clock")); break;
1133 case C1PORT: addstringtoinfstr(infstr, x_("clock1")); break;
1134 case C2PORT: addstringtoinfstr(infstr, x_("clock2")); break;
1135 case C3PORT: addstringtoinfstr(infstr, x_("clock3")); break;
1136 case C4PORT: addstringtoinfstr(infstr, x_("clock4")); break;
1137 case C5PORT: addstringtoinfstr(infstr, x_("clock5")); break;
1138 case C6PORT: addstringtoinfstr(infstr, x_("clock6")); break;
1139 case REFOUTPORT: addstringtoinfstr(infstr, x_("refout")); break;
1140 case REFINPORT: addstringtoinfstr(infstr, x_("refin")); break;
1141 case REFBASEPORT: addstringtoinfstr(infstr, x_("refbase")); break;
1142
1143 }
1144 added = TRUE;
1145 } else added = FALSE;
1146
1147 for(i=0; i<pp->numvar; i++)
1148 {
1149 var = &pp->firstvar[i];
1150 if ((var->type&VISARRAY) != 0) continue;
1151 if (!added) addtoinfstr(infstr, '['); else addtoinfstr(infstr, ',');
1152 addstringtoinfstr(infstr, (CHAR *)var->key);
1153 addtoinfstr(infstr, '=');
1154 addstringtoinfstr(infstr, describevariable(var, -1, 1));
1155 added = TRUE;
1156 }
1157 if (added) addstringtoinfstr(infstr, x_("] "));
1158
1159 addstringtoinfstr(infstr, pp->protoname);
1160 addstringtoinfstr(infstr, x_(" is "));
1161 addstringtoinfstr(infstr, cli_componentname(pp->subnodeinst));
1162 if (!cli_uniqueport(pp->subnodeinst, pp->subportproto))
1163 {
1164 addtoinfstr(infstr, ':');
1165 addstringtoinfstr(infstr, pp->subportproto->protoname);
1166 }
1167 addtoinfstr(infstr, ';');
1168 return(returninfstr(infstr));
1169 }
1170
1171 /*
1172 * routine to tell whether port "pp" of node "ni" is unique on its node
1173 * returns true if the port is unique
1174 */
cli_uniqueport(NODEINST * ni,PORTPROTO * pp)1175 BOOLEAN cli_uniqueport(NODEINST *ni, PORTPROTO *pp)
1176 {
1177 REGISTER PORTPROTO *opp;
1178 static POLYGON *poly1 = NOPOLYGON, *poly2 = NOPOLYGON;
1179
1180 /* make sure polygons are allocated */
1181 (void)needstaticpolygon(&poly1, 4, cli_constraint->cluster);
1182 (void)needstaticpolygon(&poly2, 4, cli_constraint->cluster);
1183
1184 /* get polygon for original port */
1185 shapeportpoly(ni, pp, poly1, FALSE);
1186
1187 /* look for a different port */
1188 for(opp = ni->proto->firstportproto; opp != NOPORTPROTO; opp = opp->nextportproto)
1189 {
1190 if (opp == pp) continue;
1191 shapeportpoly(ni, opp, poly2, FALSE);
1192
1193 /* if the polygons differ, this port is not unique */
1194 if (!polysame(poly1, poly2)) return(FALSE);
1195 }
1196
1197 /* all polygons the same: port is unique */
1198 return(TRUE);
1199 }
1200
1201 /*
1202 * routine to tell whether arc "ai" could be in any other layer
1203 * Returns true if the layer is unique
1204 */
cli_uniquelayer(ARCINST * ai)1205 BOOLEAN cli_uniquelayer(ARCINST *ai)
1206 {
1207 REGISTER TECHNOLOGY *tech;
1208 REGISTER ARCPROTO *ap;
1209 REGISTER PORTPROTO *pp;
1210 REGISTER INTBIG i;
1211
1212 /* clear all bits on arcs in this technology */
1213 tech = ai->proto->tech;
1214 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1215 ap->temp1 = 0;
1216
1217 /* set bits for the allowable arcs at one end of the arc */
1218 pp = ai->end[0].portarcinst->proto;
1219 for(i=0; pp->connects[i] != NOARCPROTO; i++)
1220 pp->connects[i]->temp1++;
1221
1222 /* set bits for the allowable arcs at the other end of the arc */
1223 pp = ai->end[1].portarcinst->proto;
1224 for(i=0; pp->connects[i] != NOARCPROTO; i++)
1225 pp->connects[i]->temp1++;
1226
1227 /* count the number of arcs that can connect to both ends */
1228 i = 0;
1229 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1230 if (ap->temp1 == 2) i++;
1231
1232 /* arc layer is not unique if more than one arc can make the connection */
1233 if (i > 1) return(FALSE);
1234 return(TRUE);
1235 }
1236
1237 /*
1238 * routine to add to the infinite string the size/location/rotation factors for
1239 * the component "ni" if it is not the default. Returns the number of characters
1240 * that were added to the string
1241 */
cli_addcomponentinfo(void * infstr,NODEINST * ni)1242 INTBIG cli_addcomponentinfo(void *infstr, NODEINST *ni)
1243 {
1244 CHAR line[50];
1245 REGISTER CHAR *st;
1246 REGISTER INTBIG added, i;
1247 REGISTER VARIABLE *var;
1248 INTBIG plx, phx, ply, phy;
1249
1250 /* add in component size */
1251 added = 0;
1252 if (ni->highx-ni->lowx != ni->proto->highx-ni->proto->lowx ||
1253 ni->highy-ni->lowy != ni->proto->highy-ni->proto->lowy)
1254 {
1255 nodesizeoffset(ni, &plx, &ply, &phx, &phy);
1256 (void)esnprintf(line, 50, x_("[size=(%s,%s)"), latoa(ni->highx-ni->lowx-plx-phx, 0),
1257 latoa(ni->highy-ni->lowy-ply-phy, 0));
1258 addstringtoinfstr(infstr, line);
1259 added += estrlen(line);
1260 }
1261
1262 /* add in component rotation */
1263 if (ni->rotation != 0 || ni->transpose != 0)
1264 {
1265 if (added != 0) addtoinfstr(infstr, ','); else addtoinfstr(infstr, '[');
1266 (void)esnprintf(line, 50, x_("rotation=%s"), frtoa(ni->rotation*WHOLE/10));
1267 addstringtoinfstr(infstr, line);
1268 added += estrlen(line) + 1;
1269 if (ni->transpose != 0)
1270 {
1271 addtoinfstr(infstr, 't');
1272 added++;
1273 }
1274 }
1275
1276 /* add in component location */
1277 if (ni->firstportarcinst == NOPORTARCINST)
1278 {
1279 if (added != 0) addtoinfstr(infstr, ','); else addtoinfstr(infstr, '[');
1280 (void)esnprintf(line, 50, x_("location=(%s,%s)"), latoa((ni->highx+ni->lowx) / 2, 0),
1281 latoa((ni->highy+ni->lowy) / 2, 0));
1282 addstringtoinfstr(infstr, line);
1283 added += estrlen(line) + 1;
1284 }
1285
1286 /* add additional variables */
1287 if (ni->numvar != 0) for(i=0; i<ni->numvar; i++)
1288 {
1289 var = &ni->firstvar[i];
1290 if (var->key == el_node_name_key) continue;
1291 if ((var->type&VISARRAY) != 0) continue;
1292
1293 if (added != 0) addtoinfstr(infstr, ','); else addtoinfstr(infstr, '[');
1294 added++;
1295 addstringtoinfstr(infstr, (CHAR *)var->key);
1296 addtoinfstr(infstr, '=');
1297 added += estrlen((CHAR *)var->key) + 1;
1298 st = describevariable(var, -1, 1);
1299 added += estrlen(st);
1300 addstringtoinfstr(infstr, st);
1301 }
1302
1303 if (added == 0) return(0);
1304 addtoinfstr(infstr, ']');
1305 return(added+1);
1306 }
1307
1308 /*
1309 * routine to add any options of component "compo" to the infinite string
1310 */
cli_addcomponentdata(void * infstr,COMPONENT * compo)1311 void cli_addcomponentdata(void *infstr, COMPONENT *compo)
1312 {
1313 CHAR line[50];
1314 REGISTER ATTR *a;
1315
1316 if ((compo->flag&(COMPSIZE|COMPROT|COMPLOC|COMPATTR)) != 0)
1317 {
1318 addtoinfstr(infstr, '[');
1319 if ((compo->flag&COMPSIZE) != 0)
1320 {
1321 (void)esnprintf(line, 50, x_("size=(%s,%s)"), latoa(compo->sizex, 0), latoa(compo->sizey, 0));
1322 addstringtoinfstr(infstr, line);
1323 }
1324 if ((compo->flag&COMPROT) != 0)
1325 {
1326 if ((compo->flag&COMPSIZE) != 0) addtoinfstr(infstr, ',');
1327 (void)esnprintf(line, 50, x_("rotation=%s"), frtoa(compo->rot*WHOLE/10));
1328 addstringtoinfstr(infstr, line);
1329 if (compo->trans != 0) addtoinfstr(infstr, 't');
1330 }
1331 if ((compo->flag&COMPLOC) != 0)
1332 {
1333 if ((compo->flag&(COMPSIZE|COMPROT)) != 0) addtoinfstr(infstr, ',');
1334 (void)esnprintf(line, 50, x_("location=(%s,%s)"), latoa(compo->locx, 0), latoa(compo->locy, 0));
1335 addstringtoinfstr(infstr, line);
1336 }
1337 if ((compo->flag&COMPATTR) != 0)
1338 {
1339 if ((compo->flag&(COMPSIZE|COMPROT|COMPLOC)) != 0) addtoinfstr(infstr, ',');
1340 for(a = compo->firstattr; a != NOATTR; a = a->nextattr)
1341 {
1342 if (a != compo->firstattr) addtoinfstr(infstr, ',');
1343 cli_addattr(infstr, a);
1344 }
1345 }
1346 addtoinfstr(infstr, ']');
1347 }
1348 }
1349
1350 /*
1351 * routine to return the component name for node "ni"
1352 */
cli_componentname(NODEINST * ni)1353 CHAR *cli_componentname(NODEINST *ni)
1354 {
1355 static CHAR line[50];
1356 REGISTER VARIABLE *var;
1357
1358 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
1359 if (var == NOVARIABLE)
1360 {
1361 (void)esnprintf(line, 50, x_("NODE%ld"), (INTBIG)ni);
1362 return(line);
1363 }
1364 return((CHAR *)var->addr);
1365 }
1366
cli_addcomponentline(CHAR * str,WINDOWPART * win)1367 void cli_addcomponentline(CHAR *str, WINDOWPART *win)
1368 {
1369 REGISTER INTBIG i, total;
1370
1371 total = asktool(us_tool, x_("edit-totallines"), (INTBIG)win);
1372
1373 /* search for the last line with a valid component declaration */
1374 for(i = total-1; i >= 0; i--)
1375 if (cli_linetype((CHAR *)asktool(us_tool, x_("edit-getline"), (INTBIG)win, i)) == LINEDECL) break;
1376 if (i < 0) i = 0;
1377 (void)asktool(us_tool, x_("edit-addline"), (INTBIG)win, i+1, (INTBIG)str);
1378 cli_textlines++;
1379 }
1380
cli_addattr(void * infstr,ATTR * a)1381 void cli_addattr(void *infstr, ATTR *a)
1382 {
1383 CHAR line[50];
1384
1385 addstringtoinfstr(infstr, a->name);
1386 addtoinfstr(infstr, '=');
1387 if ((a->type&VTYPE) == VINTEGER)
1388 {
1389 (void)esnprintf(line, 50, x_("%ld"), a->value);
1390 addstringtoinfstr(infstr, line);
1391 } else
1392 {
1393 addtoinfstr(infstr, '"');
1394 addstringtoinfstr(infstr, (CHAR *)a->value);
1395 addtoinfstr(infstr, '"');
1396 }
1397 }
1398
1399 /*
1400 * routine to add the name of nodeproto "np" to the inifinte string
1401 */
cli_addnodeprotoname(void * infstr,NODEPROTO * np)1402 void cli_addnodeprotoname(void *infstr, NODEPROTO *np)
1403 {
1404 if (np->primindex != 0)
1405 {
1406 if (np->tech != el_curtech)
1407 {
1408 addstringtoinfstr(infstr, np->tech->techname);
1409 addtoinfstr(infstr, ':');
1410 }
1411 addstringtoinfstr(infstr, np->protoname);
1412 } else addstringtoinfstr(infstr, np->protoname);
1413 }
1414