1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrcomoq.c
6  * User interface tool: command handler for O through Q
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "usr.h"
34 #include "egraphics.h"
35 #include "sim.h"
36 
us_offtool(INTBIG count,CHAR * par[])37 void us_offtool(INTBIG count, CHAR *par[])
38 {
39 	REGISTER INTBIG permanently;
40 
41 	if (count == 2 && namesamen(par[1], x_("permanently"), estrlen(par[1])) == 0)
42 	{
43 		count--;
44 		permanently = 1;
45 	} else permanently = 0;
46 	us_settool(count, par, permanently);
47 }
48 
us_ontool(INTBIG count,CHAR * par[])49 void us_ontool(INTBIG count, CHAR *par[])
50 {
51 	us_settool(count, par, 2);
52 }
53 
us_outhier(INTBIG count,CHAR * par[])54 void us_outhier(INTBIG count, CHAR *par[])
55 {
56 	REGISTER INTBIG len, total, i, j, haveview, vlx, vhx, vly, vhy;
57 	INTBIG lx, hx, ly, hy, index, viewinfo[22];
58 	REGISTER NODEPROTO *curnp, *hinp, *np;
59 	REGISTER BOOLEAN newwindow, found;
60 	REGISTER NODEINST *ni, *hini, *iconinst;
61 	REGISTER PORTPROTO *pp, *curpp, *hipp;
62 	REGISTER PORTEXPINST *pe;
63 	REGISTER WINDOWPART *w;
64 	REGISTER VARIABLE *var;
65 	XARRAY into, outof;
66 	HIGHLIGHT high;
67 
68 	/* make sure repeat count is valid */
69 	if (count == 0) total = 1; else
70 	{
71 		total = eatoi(par[0]);
72 		if (total <= 0)
73 		{
74 			us_abortcommand(_("Specify a positive number"));
75 			return;
76 		}
77 	}
78 
79 	/* must be editing a cell */
80 	curnp = us_needcell();
81 	if (curnp == NONODEPROTO) return;
82 
83 	/* if in waveform window, switch to associated circuit window */
84 	if ((el_curwindowpart->state&WINDOWTYPE) == WAVEFORMWINDOW)
85 	{
86 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
87 			if (w != el_curwindowpart && w->curnodeproto == curnp) break;
88 		if (w == NOWINDOWPART)
89 		{
90 			us_abortcommand(_("Cannot go up the hierarchy from this waveform window"));
91 			return;
92 		}
93 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_window_key, (INTBIG)w,
94 			VWINDOWPART|VDONTSAVE);
95 	}
96 
97 	/* initialize desired window extent */
98 	lx = el_curwindowpart->screenlx;   hx = el_curwindowpart->screenhx;
99 	ly = el_curwindowpart->screenly;   hy = el_curwindowpart->screenhy;
100 
101 	/* see if a node with an export is highlighted */
102 	curpp = NOPORTPROTO;
103 	var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
104 	if (var != NOVARIABLE)
105 	{
106 		len = getlength(var);
107 		if (len == 1)
108 		{
109 			/* get the highlighted object */
110 			if (!us_makehighlight(((CHAR **)var->addr)[0], &high))
111 			{
112 				pp = NOPORTPROTO;
113 				if ((high.status&HIGHTYPE) == HIGHTEXT)
114 				{
115 					if (high.fromvar == NOVARIABLE && high.fromport != NOPORTPROTO)
116 						pp = high.fromport->subportproto;
117 				} else
118 				{
119 					if ((high.status&HIGHTYPE) == HIGHFROM &&
120 						high.fromgeom->entryisnode && high.fromport != NOPORTPROTO)
121 							pp = high.fromport;
122 				}
123 				if (pp != NOPORTPROTO)
124 				{
125 					ni = high.fromgeom->entryaddr.ni;
126 					np = ni->proto;
127 
128 					/* see if port is an export */
129 					for (pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
130 					{
131 						if (pe->proto == pp)
132 						{
133 							curpp = pe->exportproto;
134 							break;
135 						}
136 					}
137 				}
138 			}
139 		}
140 	}
141 
142 	us_clearhighlightcount();
143 	haveview = 0;
144 	newwindow = FALSE;
145 	for(i=0; i<total; i++)
146 	{
147 		hinp = NONODEPROTO;
148 
149 		hini = descentparent(curnp, &index, el_curwindowpart, viewinfo);
150 		if (hini != NONODEINST)
151 		{
152 			hinp = hini->parent;
153 			for(j=0; j<22; j++) if (viewinfo[j] != 0) break;
154 			if (j >= 22) haveview = 0; else
155 			{
156 				haveview = 1;
157 				vlx         = viewinfo[0];
158 				vhx         = viewinfo[1];
159 				vly         = viewinfo[2];
160 				vhy         = viewinfo[3];
161 				into[0][0]  = viewinfo[4];
162 				into[0][1]  = viewinfo[5];
163 				into[0][2]  = viewinfo[6];
164 				into[1][0]  = viewinfo[7];
165 				into[1][1]  = viewinfo[8];
166 				into[1][2]  = viewinfo[9];
167 				into[2][0]  = viewinfo[10];
168 				into[2][1]  = viewinfo[11];
169 				into[2][2]  = viewinfo[12];
170 				outof[0][0] = viewinfo[13];
171 				outof[0][1] = viewinfo[14];
172 				outof[0][2] = viewinfo[15];
173 				outof[1][0] = viewinfo[16];
174 				outof[1][1] = viewinfo[17];
175 				outof[1][2] = viewinfo[18];
176 				outof[2][0] = viewinfo[19];
177 				outof[2][1] = viewinfo[20];
178 				outof[2][2] = viewinfo[21];
179 			}
180 		}
181 
182 		/* if stack didn't tell where to go, see if upper cell is obvious */
183 		if (hinp == NONODEPROTO)
184 		{
185 			/* see if cell "curnp" has an icon cell */
186 			np = iconview(curnp);
187 			if (np == NONODEPROTO) np = curnp;
188 
189 			/* see if there is any instance of that cell */
190 			found = FALSE;
191 			hinp = NONODEPROTO;
192 			iconinst = NONODEINST;
193 			for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
194 			{
195 				if (isiconof(np, ni->parent))
196 				{
197 					iconinst = ni;
198 					continue;
199 				}
200 				if ((ni->parent->lib->userbits&HIDDENLIBRARY) != 0) continue;
201 				found = TRUE;
202 				if (hinp != NONODEPROTO)
203 				{
204 					if (ni->parent == hinp) continue;
205 					hinp = NONODEPROTO;
206 					break;
207 				}
208 				hinp = ni->parent;
209 				hini = ni;
210 			}
211 			if (!found && iconinst != NONODEINST)
212 			{
213 				hini = iconinst;
214 				hinp = iconinst->parent;
215 				found = TRUE;
216 			}
217 			if (!found)
218 			{
219 				if (i == 0)
220 				{
221 					us_abortcommand(_("Not in any cells"));
222 					return;
223 				}
224 				ttyputerr(_("Only in %ld deep"), i);
225 				hinp = curnp;
226 				break;
227 			}
228 			if (hinp == NONODEPROTO)
229 			{
230 				hini = us_pickhigherinstance(np);
231 				if (hini == NONODEINST) return;
232 				newwindow = TRUE;
233 				hinp = hini->parent;
234 			}
235 		}
236 
237 		/* determine which port to highlight */
238 		hipp = NOPORTPROTO;
239 		if (hini != NONODEINST && curpp != NOPORTPROTO)
240 			hipp = equivalentport(curnp, curpp, hini->proto);
241 
242 		/* adjust view of the cell */
243 		if (haveview != 0)
244 		{
245 			lx = vlx;   hx = vhx;
246 			ly = vly;   hy = vhy;
247 		} else
248 		{
249 			if (hini != NONODEINST && hini->proto == curnp)
250 			{
251 				lx += hini->geom->lowx - curnp->lowx;
252 				hx += hini->geom->lowx - curnp->lowx;
253 				ly += hini->geom->lowy - curnp->lowy;
254 				hy += hini->geom->lowy - curnp->lowy;
255 			} else
256 			{
257 				/* make a full view of the cell */
258 				us_fullview(hinp, &lx, &hx, &ly, &hy);
259 			}
260 		}
261 
262 		/* keep rolling up the hierarchy */
263 		curnp = hinp;
264 		curpp = hipp;
265 	}
266 
267 	/* display the final location */
268 	if (haveview != 0)
269 	{
270 		us_setxarray((INTBIG)el_curwindowpart, VWINDOWPART, x_("intocell"), into);
271 		us_setxarray((INTBIG)el_curwindowpart, VWINDOWPART, x_("outofcell"), outof);
272 		if (outof[2][0] == 0 && outof[2][1] == 0 && outof[2][2] == 0)
273 		{
274 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("state"),
275 				el_curwindowpart->state & ~INPLACEEDIT, VINTEGER);
276 		} else
277 		{
278 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("state"),
279 				el_curwindowpart->state | INPLACEEDIT, VINTEGER);
280 			(void)setval((INTBIG)el_curwindowpart, VWINDOWPART, x_("inplacedepth"),
281 				el_curwindowpart->inplacedepth-1, VINTEGER);
282 		}
283 	}
284 	us_switchtocell(hinp, lx, hx, ly, hy, hini, hipp, newwindow, TRUE, TRUE);
285 
286 	/* if simulating, coordinate this hierarchy traversal with the waveform */
287 	if (el_curwindowpart != NOWINDOWPART &&
288 		(el_curwindowpart->state&WINDOWMODE) == WINDOWSIMMODE)
289 	{
290 		asktool(sim_tool, "traverse-up", (INTBIG)hinp);
291 	}
292 }
293 
us_package(INTBIG count,CHAR * par[])294 void us_package(INTBIG count, CHAR *par[])
295 {
296 	INTBIG lx, hx, ly, hy;
297 	REGISTER INTBIG search, len;
298 	REGISTER void *infstr;
299 	REGISTER GEOM *look;
300 	REGISTER NODEPROTO *np, *parnt;
301 	REGISTER PORTPROTO *ppt, *npt;
302 	REGISTER NODEINST *ni, *newni;
303 	REGISTER ARCINST *ai, *newar;
304 	REGISTER LIBRARY *lib;
305 	REGISTER CHAR *pt;
306 	extern COMCOMP us_packagep;
307 
308 	/* get the specified area */
309 	if (us_getareabounds(&lx, &hx, &ly, &hy) == NONODEPROTO)
310 	{
311 		us_abortcommand(_("Enclose an area to be packaged"));
312 		return;
313 	}
314 
315 	if (count == 0)
316 	{
317 		count = ttygetparam(M_("New cell name: "), &us_packagep, MAXPARS, par);
318 		if (count == 0)
319 		{
320 			us_abortedmsg();
321 			return;
322 		}
323 	}
324 
325 	/* figure out which library to use */
326 	lib = el_curlib;
327 	for(pt = par[0]; *pt != 0; pt++) if (*pt == ':') break;
328 	if (*pt == ':')
329 	{
330 		*pt++ = 0;
331 		lib = getlibrary(par[0]);
332 		if (lib == NOLIBRARY)
333 		{
334 			us_abortcommand(_("Cannot find library '%s'"), par[0]);
335 			return;
336 		}
337 		par[0] = pt;
338 	}
339 
340 	/* make sure there is a proper view type on this new cell */
341 	parnt = getcurcell();
342 	len = strlen(par[0]);
343 	if (par[0][len-1] != '}')
344 	{
345 		infstr = initinfstr();
346 		formatinfstr(infstr, "%s{%s}", par[0], parnt->cellview->sviewname);
347 		par[0] = returninfstr(infstr);
348 	}
349 
350 	/* create the new cell */
351 	np = us_newnodeproto(par[0], lib);
352 	if (np == NONODEPROTO)
353 	{
354 		us_abortcommand(_("Cannot create cell %s"), par[0]);
355 		return;
356 	}
357 
358 	/* first zap all nodes touching all arcs in the region */
359 	search = initsearch(lx, hx, ly, hy, parnt);
360 	for(;;)
361 	{
362 		look = nextobject(search);
363 		if (look == NOGEOM) break;
364 		if (look->entryisnode) continue;
365 		ai = look->entryaddr.ai;
366 		ni = NONODEINST;
367 		ai->end[0].nodeinst->temp1 = (UINTBIG)ni;
368 		ai->end[1].nodeinst->temp1 = (UINTBIG)ni;
369 	}
370 
371 	/* copy the nodes into the new cell */
372 	search = initsearch(lx, hx, ly, hy, parnt);
373 	for(;;)
374 	{
375 		look = nextobject(search);
376 		if (look == NOGEOM) break;
377 		if (!look->entryisnode) continue;
378 		ni = look->entryaddr.ni;
379 		newni = newnodeinst(ni->proto, ni->lowx, ni->highx, ni->lowy,
380 			ni->highy, ni->transpose, ni->rotation, np);
381 		if (newni == NONODEINST)
382 		{
383 			us_abortcommand(_("Cannot create node in new cell"));
384 			return;
385 		}
386 		ni->temp1 = (INTBIG)newni;
387 		newni->userbits = ni->userbits;
388 		TDCOPY(newni->textdescript, ni->textdescript);
389 		if (copyvars((INTBIG)ni, VNODEINST, (INTBIG)newni, VNODEINST, FALSE))
390 		{
391 			ttyputnomemory();
392 			return;
393 		}
394 
395 		/* make ports where this nodeinst has them */
396 		if (ni->firstportexpinst != NOPORTEXPINST)
397 			for(ppt = parnt->firstportproto; ppt != NOPORTPROTO; ppt = ppt->nextportproto)
398 		{
399 			if (ppt->subnodeinst != ni) continue;
400 			npt = newportproto(np, newni, ppt->subportproto, ppt->protoname);
401 			if (npt != NOPORTPROTO)
402 			{
403 				npt->userbits = (npt->userbits & ~STATEBITS) | (ppt->userbits & STATEBITS);
404 				TDCOPY(npt->textdescript, ppt->textdescript);
405 				if (copyvars((INTBIG)ppt, VPORTPROTO, (INTBIG)npt, VPORTPROTO, FALSE))
406 				{
407 					ttyputnomemory();
408 					return;
409 				}
410 			}
411 		}
412 	}
413 
414 	/* copy the arcs into the new cell */
415 	search = initsearch(lx, hx, ly, hy, parnt);
416 	for(;;)
417 	{
418 		look = nextobject(search);
419 		if (look == NOGEOM) break;
420 		if (look->entryisnode) continue;
421 		ai = look->entryaddr.ai;
422 		if (ai->end[0].nodeinst->temp1 == (UINTBIG)-1 ||
423 			ai->end[1].nodeinst->temp1 == (UINTBIG)-1) continue;
424 		newar = newarcinst(ai->proto, ai->width, ai->userbits, (NODEINST *)ai->end[0].nodeinst->temp1,
425 			ai->end[0].portarcinst->proto, ai->end[0].xpos,ai->end[0].ypos,
426 				(NODEINST *)ai->end[1].nodeinst->temp1, ai->end[1].portarcinst->proto,
427 					ai->end[1].xpos,ai->end[1].ypos, np);
428 		if (newar == NOARCINST)
429 		{
430 			us_abortcommand(_("Cannot create arc in new cell"));
431 			return;
432 		}
433 		if (copyvars((INTBIG)ai, VARCINST, (INTBIG)newar, VARCINST, FALSE) ||
434 			copyvars((INTBIG)ai->end[0].portarcinst, VPORTARCINST,
435 				(INTBIG)newar->end[0].portarcinst, VPORTARCINST, FALSE) ||
436 			copyvars((INTBIG)ai->end[1].portarcinst, VPORTARCINST,
437 				(INTBIG)newar->end[1].portarcinst, VPORTARCINST, FALSE))
438 		{
439 			ttyputnomemory();
440 			return;
441 		}
442 	}
443 
444 	/* recompute bounds of new cell */
445 	(*el_curconstraint->solve)(np);
446 
447 	ttyputmsg(_("Cell %s created"), describenodeproto(np));
448 }
449 
us_port(INTBIG count,CHAR * par[])450 void us_port(INTBIG count, CHAR *par[])
451 {
452 	REGISTER INTBIG i, l, labels, total, reducehighlighting;
453 	INTBIG lx, hx, ly, hy, mlx, mly, mhx, mhy, bits, mask, newbits, x, y, deleted;
454 	REGISTER BOOLEAN nodegood;
455 	REGISTER NODEINST *ni, *oni;
456 	REGISTER NODEPROTO *np;
457 	REGISTER PORTPROTO *pp, *ppt;
458 	REGISTER PORTARCINST *pi;
459 	REGISTER PORTEXPINST *pe, *nextpe;
460 	REGISTER LIBRARY *olib;
461 	GEOM *fromgeom, *togeom;
462 	PORTPROTO *fromport, *toport;
463 	REGISTER CHAR *pt;
464 	CHAR *portname, *refname;
465 	NODEINST **nilist;
466 	REGISTER HIGHLIGHT *high;
467 	HIGHLIGHT newhigh;
468 	extern COMCOMP us_portp, us_portep;
469 	REGISTER GEOM **g;
470 	static POLYGON *poly = NOPOLYGON;
471 	REGISTER void *infstr;
472 
473 	/* get options */
474 	if (count == 0)
475 	{
476 		count = ttygetparam(M_("Port option: "), &us_portp, MAXPARS, par);
477 		if (count == 0)
478 		{
479 			us_abortedmsg();
480 			return;
481 		}
482 	}
483 	l = estrlen(pt = par[0]);
484 
485 	if (namesamen(pt, x_("labels"), l) == 0 && l >= 1)
486 	{
487 		if (count > 1)
488 		{
489 			l = estrlen(pt = par[1]);
490 			if (namesamen(pt, x_("crosses"), l) == 0 && l >= 1) labels = PORTSCROSS; else
491 			if (namesamen(pt, x_("short"), l) == 0 && l >= 2) labels = PORTSSHORT; else
492 			if (namesamen(pt, x_("long"), l) == 0 && l >= 1) labels = PORTSFULL; else
493 			{
494 				ttyputusage(x_("port labels short|long|crosses"));
495 				return;
496 			}
497 			startobjectchange((INTBIG)us_tool, VTOOL);
498 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
499 				(us_useroptions & ~PORTLABELS) | labels, VINTEGER);
500 			endobjectchange((INTBIG)us_tool, VTOOL);
501 		}
502 		switch (us_useroptions&PORTLABELS)
503 		{
504 			case PORTSCROSS: ttyputverbose(M_("Ports shown as crosses"));     break;
505 			case PORTSFULL:  ttyputverbose(M_("Long port names displayed"));  break;
506 			case PORTSSHORT: ttyputverbose(M_("Short port names displayed")); break;
507 		}
508 		return;
509 	}
510 
511 	if (namesamen(pt, x_("export-labels"), l) == 0 && l >= 8)
512 	{
513 		if (count > 1)
514 		{
515 			l = estrlen(pt = par[1]);
516 			if (namesamen(pt, x_("crosses"), l) == 0 && l >= 1) labels = EXPORTSCROSS; else
517 			if (namesamen(pt, x_("short"), l) == 0 && l >= 2) labels = EXPORTSSHORT; else
518 			if (namesamen(pt, x_("long"), l) == 0 && l >= 1) labels = EXPORTSFULL; else
519 			{
520 				ttyputusage(x_("port export-labels short|long|crosses"));
521 				return;
522 			}
523 			startobjectchange((INTBIG)us_tool, VTOOL);
524 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
525 				(us_useroptions & ~EXPORTLABELS) | labels, VINTEGER);
526 			endobjectchange((INTBIG)us_tool, VTOOL);
527 		}
528 		switch (us_useroptions&EXPORTLABELS)
529 		{
530 			case EXPORTSCROSS: ttyputverbose(M_("Exports shown as crosses"));     break;
531 			case EXPORTSFULL:  ttyputverbose(M_("Long export names displayed"));  break;
532 			case EXPORTSSHORT: ttyputverbose(M_("Short export names displayed")); break;
533 		}
534 		return;
535 	}
536 
537 	if (namesamen(pt, x_("synchronize-library"), l) == 0 && l >= 1)
538 	{
539 		if (count <= 1)
540 		{
541 			ttyputusage(x_("port synchronize-library LIBRARY"));
542 			return;
543 		}
544 		olib = getlibrary(par[1]);
545 		if (olib == NOLIBRARY)
546 		{
547 			us_abortcommand(_("No library called %s is read in"), par[1]);
548 			return;
549 		}
550 		if (olib == el_curlib)
551 		{
552 			us_abortcommand(_("Must synchronize with a different library"));
553 			return;
554 		}
555 		us_portsynchronize(olib);
556 		return;
557 	}
558 
559 	if (namesamen(pt, x_("identify-cell"), l) == 0 && l >= 10)
560 	{
561 		/* make sure there is a current cell */
562 		np = us_needcell();
563 		if (np == NONODEPROTO) return;
564 		if ((el_curwindowpart->state&WINDOWTYPE) == DISP3DWINDOW)
565 		{
566 			us_abortcommand(_("Cannot show exports in a 3D window"));
567 			return;
568 		}
569 		us_identifyports(0, 0, np, LAYERA, FALSE);
570 		return;
571 	}
572 
573 	if (namesamen(pt, x_("identify-node"), l) == 0 && l >= 10)
574 	{
575 		/* make sure there is a current node */
576 		if ((el_curwindowpart->state&WINDOWTYPE) == DISP3DWINDOW)
577 		{
578 			us_abortcommand(_("Cannot show ports in a 3D window"));
579 			return;
580 		}
581 		g = us_gethighlighted(WANTNODEINST, 0, 0);
582 		for(i=0; g[i] != NOGEOM; i++) ;
583 		if (i <= 0)
584 		{
585 			us_abortcommand(_("Must select one or more nodes"));
586 			return;
587 		}
588 		nilist = (NODEINST **)emalloc(i * (sizeof (NODEINST *)), el_tempcluster);
589 		if (nilist == 0) return;
590 		for(i=0; g[i] != NOGEOM; i++)
591 			nilist[i] = g[i]->entryaddr.ni;
592 		us_identifyports(i, nilist, nilist[0]->proto, LAYERA, FALSE);
593 		efree((CHAR *)nilist);
594 		return;
595 	}
596 
597 	if (namesamen(pt, x_("move"), l) == 0 && l >= 1)
598 	{
599 		if (us_gettwoobjects(&fromgeom, &fromport, &togeom, &toport))
600 		{
601 			us_abortcommand(_("Must select two nodes"));
602 			return;
603 		}
604 		if (fromport == NOPORTPROTO || toport == NOPORTPROTO)
605 		{
606 			us_abortcommand(_("Must select two nodes AND their ports"));
607 			return;
608 		}
609 
610 		/* make sure ports are in the same cell */
611 		np = geomparent(fromgeom);
612 		if (np != geomparent(togeom))
613 		{
614 			us_abortcommand(_("Port motion must be within a single cell"));
615 			return;
616 		}
617 
618 		/* disallow port action if lock is on */
619 		if (us_cantedit(np, NONODEINST, TRUE)) return;
620 
621 		reducehighlighting = 1;
622 		if (count > 1)
623 		{
624 			l = estrlen(pt = par[1]);
625 			if (namesamen(pt, x_("remain-highlighted"), l) == 0) reducehighlighting = 0;
626 		}
627 
628 		/* get the "source" node and export */
629 		oni = fromgeom->entryaddr.ni;
630 		for(pe = oni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
631 			if (pe->proto == fromport) break;
632 		if (pe == NOPORTEXPINST)
633 		{
634 			us_abortcommand(_("Port %s of node %s is not an export"), fromport->protoname,
635 				describenodeinst(oni));
636 			return;
637 		}
638 
639 		/* move the port */
640 		ni = togeom->entryaddr.ni;
641 		if (ni == oni && fromport == toport)
642 		{
643 			us_abortcommand(_("This does not move the port"));
644 			return;
645 		}
646 
647 		/* clear highlighting */
648 		if (reducehighlighting == 0) us_pushhighlight();
649 		us_clearhighlightcount();
650 
651 		np = ni->parent;
652 		pt = pe->exportproto->protoname;
653 		startobjectchange((INTBIG)ni, VNODEINST);
654 		startobjectchange((INTBIG)oni, VNODEINST);
655 		if (moveportproto(np, pe->exportproto, ni, toport)) ttyputerr(_("Port not moved")); else
656 		{
657 			endobjectchange((INTBIG)ni, VNODEINST);
658 			endobjectchange((INTBIG)oni, VNODEINST);
659 			ttyputverbose(M_("Port %s moved from node %s to node %s"), pt, describenodeinst(oni),
660 				describenodeinst(ni));
661 		}
662 
663 		/* restore highlighting */
664 		if (reducehighlighting == 0) us_pophighlight(FALSE); else
665 		{
666 			newhigh.status = HIGHFROM;
667 			newhigh.cell = np;
668 			newhigh.fromgeom = fromgeom;
669 			newhigh.fromport = fromport;
670 			us_addhighlight(&newhigh);
671 		}
672 		return;
673 	}
674 
675 	if (namesamen(pt, x_("re-export-all"), l) == 0 && l >= 1)
676 	{
677 		/* make sure there is a current cell */
678 		np = us_needcell();
679 		if (np == NONODEPROTO) return;
680 
681 		/* disallow port action if lock is on */
682 		if (us_cantedit(np, NONODEINST, TRUE)) return;
683 
684 		/* save highlighting */
685 		us_pushhighlight();
686 		us_clearhighlightcount();
687 
688 		/* look at every node in this cell */
689 		total = 0;
690 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
691 		{
692 			/* only look for cells, not primitives */
693 			if (ni->proto->primindex != 0) continue;
694 
695 			/* ignore recursive references (showing icon in contents) */
696 			if (isiconof(ni->proto, np)) continue;
697 
698 			/* clear marks on the ports of this node */
699 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
700 				pp->temp1 = 0;
701 
702 			/* mark the connected and exports */
703 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
704 				pi->proto->temp1++;
705 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
706 				pe->proto->temp1++;
707 
708 			/* initialize for queueing creation of new exports */
709 			us_initqueuedexports();
710 
711 			/* now export the remaining ports */
712 			nodegood = FALSE;
713 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
714 				if (pp->temp1 == 0)
715 			{
716 				if (!nodegood)
717 				{
718 					startobjectchange((INTBIG)ni, VNODEINST);
719 					nodegood = TRUE;
720 				}
721 				if (us_queuenewexport(ni, pp, pp))
722 				{
723 					us_pophighlight(FALSE);
724 					return;
725 				}
726 				total++;
727 			}
728 			if (nodegood)
729 			{
730 				/* create any queued exports */
731 				us_createqueuedexports();
732 				endobjectchange((INTBIG)ni, VNODEINST);
733 			}
734 		}
735 		if (total == 0) ttyputmsg(_("No ports to export")); else
736 			ttyputmsg(_("%ld ports exported"), total);
737 
738 		/* restore highlighting */
739 		us_pophighlight(FALSE);
740 		return;
741 	}
742 
743 	if (namesamen(pt, x_("highlighted-re-export"), l) == 0 && l >= 1)
744 	{
745 		/* get the necessary polygon */
746 		(void)needstaticpolygon(&poly, 4, us_tool->cluster);
747 
748 		/* get the bounds of the selected area */
749 		np = us_getareabounds(&lx, &hx, &ly, &hy);
750 		if (np == NONODEPROTO)
751 		{
752 			us_abortcommand(_("Must select an area enclosing ports to export"));
753 			return;
754 		}
755 
756 		/* disallow port action if lock is on */
757 		if (us_cantedit(np, NONODEINST, TRUE)) return;
758 
759 		/* get list of nodes in the selected area */
760 		g = us_gethighlighted(WANTNODEINST, 0, 0);
761 		if (g[0] == NOGEOM)
762 		{
763 			us_abortcommand(_("Must select some nodes for making exports"));
764 			return;
765 		}
766 
767 		/* save highlighting */
768 		us_pushhighlight();
769 		us_clearhighlightcount();
770 
771 		/* initialize for queueing creation of new exports */
772 		us_initqueuedexports();
773 
774 		/* re-export the requested ports */
775 		total = 0;
776 		for(i=0; g[i] != NOGEOM; i++)
777 		{
778 			ni = g[i]->entryaddr.ni;
779 
780 			/* only look for cells, not primitives */
781 			if (ni->proto->primindex != 0) continue;
782 
783 			/* clear marks on the ports of this node */
784 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
785 				pp->temp1 = 0;
786 
787 			/* mark the connected and make exports */
788 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
789 				pi->proto->temp1++;
790 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
791 				pe->proto->temp1++;
792 
793 			/* now export the remaining ports that are in the area */
794 			nodegood = FALSE;
795 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
796 				if (pp->temp1 == 0)
797 			{
798 				shapeportpoly(ni, pp, poly, FALSE);
799 				getbbox(poly, &mlx, &mhx, &mly, &mhy);
800 				if (mlx > hx || mhx < lx || mly > hy || mhy < ly) continue;
801 				if (!nodegood)
802 				{
803 					startobjectchange((INTBIG)ni, VNODEINST);
804 					nodegood = TRUE;
805 				}
806 				if (us_queuenewexport(ni, pp, pp))
807 				{
808 					us_pophighlight(FALSE);
809 					return;
810 				}
811 				total++;
812 			}
813 		}
814 
815 		/* create any queued exports */
816 		us_createqueuedexports();
817 		for(i=0; g[i] != NOGEOM; i++)
818 		{
819 			ni = g[i]->entryaddr.ni;
820 			if (ni->proto->primindex != 0) continue;
821 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
822 			{
823 				if (pp->temp1 != 0) continue;
824 				endobjectchange((INTBIG)ni, VNODEINST);
825 				break;
826 			}
827 		}
828 		if (total == 0) ttyputmsg(_("No ports to export")); else
829 			ttyputmsg(_("%ld ports exported"), total);
830 
831 		/* restore highlighting */
832 		us_pophighlight(FALSE);
833 		return;
834 	}
835 
836 	if (namesamen(pt, x_("power-ground-re-export"), l) == 0 && l >= 1)
837 	{
838 		/* make sure there is a current cell */
839 		np = us_needcell();
840 		if (np == NONODEPROTO) return;
841 
842 		/* disallow port action if lock is on */
843 		if (us_cantedit(np, NONODEINST, TRUE)) return;
844 
845 		/* save highlighting */
846 		us_pushhighlight();
847 		us_clearhighlightcount();
848 
849 		/* look at every node in this cell */
850 		total = 0;
851 		for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
852 		{
853 			/* only look for cells, not primitives */
854 			if (ni->proto->primindex != 0) continue;
855 
856 			/* ignore recursive references (showing icon in contents) */
857 			if (isiconof(ni->proto, np)) continue;
858 
859 			/* clear marks on the ports of this node */
860 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
861 				pp->temp1 = 0;
862 
863 			/* mark the connected and exports */
864 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
865 				pi->proto->temp1++;
866 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
867 				pe->proto->temp1++;
868 
869 			/* now export the remaining power and ground ports */
870 			for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
871 			{
872 				if (pp->temp1 != 0) continue;
873 				if (!portispower(pp) && !portisground(pp)) continue;
874 
875 				if (us_reexportport(pp, ni))
876 				{
877 					us_pophighlight(FALSE);
878 					return;
879 				}
880 				total++;
881 			}
882 		}
883 		if (total == 0) ttyputmsg(_("No power and ground ports to export")); else
884 			ttyputmsg(_("%ld power and ground ports exported"), total);
885 
886 		/* restore highlighting */
887 		us_pophighlight(FALSE);
888 		return;
889 	}
890 
891 	if (namesamen(pt, x_("not"), l) == 0 && l >= 1)
892 	{
893 		if (count <= 1 || namesamen(par[1], x_("export"), estrlen(par[1])) != 0)
894 		{
895 			ttyputusage(x_("port not export [OPTIONS]"));
896 			return;
897 		}
898 		if (count == 3 && namesame(par[2], x_("geometry")) == 0)
899 		{
900 			/* delete ports in selected area */
901 			np = us_getareabounds(&lx, &hx, &ly, &hy);
902 			if (np == NONODEPROTO)
903 			{
904 				us_abortcommand(_("Outline an area first"));
905 				return;
906 			}
907 
908 			/* get the necessary polygon */
909 			(void)needstaticpolygon(&poly, 4, us_tool->cluster);
910 
911 			/* remove highlighting */
912 			us_pushhighlight();
913 			us_clearhighlightcount();
914 
915 			deleted = 0;
916 			for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
917 			{
918 				i = 0;
919 				for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = nextpe)
920 				{
921 					nextpe = pe->nextportexpinst;
922 					shapeportpoly(ni, pe->proto, poly, FALSE);
923 					getcenter(poly, &x, &y);
924 					if (x < lx || x > hx || y < ly || y > hy) continue;
925 					ttyputmsg(_("Deleting port %s"), pe->exportproto->protoname);
926 					if (i == 0) startobjectchange((INTBIG)ni, VNODEINST);
927 					if (killportproto(np, pe->exportproto))
928 						ttyputerr(_("killportproto error"));
929 					i = 1;
930 					deleted++;
931 				}
932 				if (i != 0) endobjectchange((INTBIG)ni, VNODEINST);
933 			}
934 
935 			/* restore highlighting */
936 			us_pophighlight(FALSE);
937 			if (deleted == 0) ttyputmsg(_("No exports are in the selected area"));
938 			return;
939 		}
940 		if (count == 3 && namesame(par[2], x_("all")) == 0)
941 		{
942 			g = us_gethighlighted(WANTNODEINST, 0, 0);
943 			if (g[0] == NOGEOM)
944 			{
945 				us_abortcommand(_("Must first select nodes with exports"));
946 				return;
947 			}
948 
949 			/* remove highlighting */
950 			us_pushhighlight();
951 			us_clearhighlightcount();
952 
953 			/* delete ports from all selected node */
954 			deleted = 0;
955 			for(i=0; g[i] != NOGEOM; i++)
956 			{
957 				ni = g[i]->entryaddr.ni;
958 				if (ni->firstportexpinst == NOPORTEXPINST) continue;
959 
960 				/* remove the port(s) */
961 				startobjectchange((INTBIG)ni, VNODEINST);
962 				for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = nextpe)
963 				{
964 					nextpe = pe->nextportexpinst;
965 					ttyputmsg(_("Deleting export %s"), pe->exportproto->protoname);
966 					if (killportproto(ni->parent, pe->exportproto))
967 						ttyputerr(_("killportproto error"));
968 					deleted++;
969 				}
970 				endobjectchange((INTBIG)ni, VNODEINST);
971 			}
972 
973 			/* restore highlighting */
974 			us_pophighlight(FALSE);
975 			if (deleted == 0) ttyputmsg(_("No exports are on the selected nodes"));
976 			return;
977 		}
978 
979 		/* delete only the selected port */
980 		high = us_getonehighlight();
981 		if (high == NOHIGHLIGHT) return;
982 		if ((high->status&HIGHTYPE) == HIGHTEXT)
983 		{
984 			if (high->fromvar != NOVARIABLE || high->fromport == NOPORTPROTO)
985 			{
986 				us_abortcommand(_("Selected text must be a port name"));
987 				return;
988 			}
989 			ni = high->fromgeom->entryaddr.ni;
990 			ppt = high->fromport;
991 		} else
992 		{
993 			ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
994 			if (ni == NONODEINST) return;
995 			ppt = NOPORTPROTO;
996 		}
997 
998 		/* first see if there is a port on this nodeinst */
999 		if (ni->firstportexpinst == NOPORTEXPINST)
1000 		{
1001 			us_abortcommand(_("No exports on this node"));
1002 			return;
1003 		}
1004 
1005 		/* disallow port action if lock is on */
1006 		if (us_cantedit(ni->parent, NONODEINST, TRUE)) return;
1007 
1008 		/* get the specification details */
1009 		pp = us_portdetails(ppt, count-2, &par[2], ni, &bits, &mask, TRUE, x_(""), &refname);
1010 		if (pp == NOPORTPROTO) return;
1011 
1012 		/* remove highlighting */
1013 		us_pushhighlight();
1014 		us_clearhighlightcount();
1015 
1016 		/* remove the port(s) */
1017 		startobjectchange((INTBIG)ni, VNODEINST);
1018 		us_undoportproto(ni, pp);
1019 		endobjectchange((INTBIG)ni, VNODEINST);
1020 
1021 		/* restore highlighting */
1022 		us_pophighlight(FALSE);
1023 
1024 		ttyputverbose(M_("Port %s deleted"), pp->protoname);
1025 		return;
1026 	}
1027 
1028 	if (namesamen(pt, x_("export"), l) == 0 && l >= 1)
1029 	{
1030 		ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
1031 		if (ni == NONODEINST) return;
1032 
1033 		/* disallow port action if lock is on */
1034 		if (us_cantedit(ni->parent, NONODEINST, TRUE)) return;
1035 
1036 		if (count <= 1)
1037 		{
1038 			count = ttygetparam(M_("Port name: "), &us_portep, MAXPARS-1, &par[1])+1;
1039 			if (count <= 1)
1040 			{
1041 				us_abortedmsg();
1042 				return;
1043 			}
1044 		}
1045 
1046 		/* check name for validity */
1047 		pt = par[1];
1048 		while (*pt == ' ') pt++;
1049 		if (*pt == 0)
1050 		{
1051 			us_abortcommand(_("Null name"));
1052 			return;
1053 		}
1054 
1055 		/* find a unique port name */
1056 		portname = us_uniqueportname(pt, ni->parent);
1057 		if (namesame(portname, pt) != 0)
1058 			ttyputmsg(_("Already a port called %s, calling this %s"), pt, portname);
1059 
1060 		/* get the specification details */
1061 		pp = us_portdetails(NOPORTPROTO, count-2, &par[2], ni, &bits, &mask, FALSE, pt, &refname);
1062 		if (pp == NOPORTPROTO) return;
1063 
1064 		/* save highlighting */
1065 		us_pushhighlight();
1066 		us_clearhighlightcount();
1067 
1068 		/* make the port */
1069 		pp = us_makenewportproto(ni->parent, ni, pp, portname, mask, bits, pp->textdescript);
1070 		if (*refname != 0)
1071 			setval((INTBIG)pp, VPORTPROTO, x_("EXPORT_reference_name"), (INTBIG)refname, VSTRING);
1072 
1073 		/* restore highlighting */
1074 		us_pophighlight(FALSE);
1075 
1076 		ttyputverbose(M_("Port %s created"), pp->protoname);
1077 		return;
1078 	}
1079 
1080 	if (namesamen(pt, x_("change"), l) == 0 && l >= 1)
1081 	{
1082 		high = us_getonehighlight();
1083 		if (high == NOHIGHLIGHT) return;
1084 		if ((high->status&HIGHTYPE) == HIGHTEXT)
1085 		{
1086 			if (high->fromvar != NOVARIABLE || high->fromport == NOPORTPROTO)
1087 			{
1088 				us_abortcommand(_("Selected text must be a port name"));
1089 				return;
1090 			}
1091 			ni = high->fromgeom->entryaddr.ni;
1092 			ppt = high->fromport;
1093 		} else
1094 		{
1095 			ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
1096 			if (ni == NONODEINST) return;
1097 			ppt = NOPORTPROTO;
1098 		}
1099 
1100 		/* disallow port action if lock is on */
1101 		if (us_cantedit(ni->parent, NONODEINST, TRUE)) return;
1102 
1103 		/* get the specification details */
1104 		pp = us_portdetails(ppt, count-1, &par[1], ni, &bits, &mask, TRUE, x_(""), &refname);
1105 		if (pp == NOPORTPROTO) return;
1106 
1107 		/* change the port characteristics */
1108 		newbits = pp->userbits;
1109 		if ((mask&STATEBITS) != 0)
1110 			newbits = (newbits & ~STATEBITS) | (bits & STATEBITS);
1111 		if ((mask&PORTDRAWN) != 0)
1112 			newbits = (newbits & ~PORTDRAWN) | (bits & PORTDRAWN);
1113 		if ((mask&BODYONLY) != 0)
1114 			newbits = (newbits & ~BODYONLY) | (bits & BODYONLY);
1115 		setval((INTBIG)pp, VPORTPROTO, x_("userbits"), newbits, VINTEGER);
1116 
1117 		/* propagate the change information up the hierarchy */
1118 		changeallports(pp);
1119 
1120 		infstr = initinfstr();
1121 		formatinfstr(infstr, _("Port '%s'"), pp->protoname);
1122 		if ((pp->userbits&STATEBITS) == 0)
1123 			addstringtoinfstr(infstr, _(" has no characteristics")); else
1124 		{
1125 			formatinfstr(infstr, _(" is %s"), describeportbits(pp->userbits));
1126 		}
1127 		formatinfstr(infstr, _(" (label %s"), us_describetextdescript(pp->textdescript));
1128 		if ((pp->userbits&PORTDRAWN) != 0) addstringtoinfstr(infstr, _(",always-drawn"));
1129 		if ((pp->userbits&BODYONLY) != 0) addstringtoinfstr(infstr, _(",only-on-body"));
1130 		addstringtoinfstr(infstr, x_(") "));
1131 		ttyputmsg(x_("%s"), returninfstr(infstr));
1132 		return;
1133 	}
1134 
1135 	ttyputbadusage(x_("port"));
1136 }
1137 
us_quit(INTBIG count,CHAR * par[])1138 void us_quit(INTBIG count, CHAR *par[])
1139 {
1140 	if (us_preventloss(NOLIBRARY, 0, TRUE)) return;
1141 	bringdown();
1142 }
1143