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