1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usrcomtz.c
6  * User interface tool: command handler for T through V
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "global.h"
33 #include "egraphics.h"
34 #include "edialogs.h"
35 #include "usr.h"
36 #include "usrtrack.h"
37 #include "tecgen.h"
38 #include "efunction.h"
39 
40 /* working memory for "us_var()" */
41 static INTBIG *us_varaddr1, *us_vartype1, us_varlimit1=0;
42 static INTBIG *us_varaddr2, *us_vartype2, us_varlimit2=0;
43 static INTBIG *us_varaddr3, *us_vartype3, us_varlimit3=0;
44 static CHAR *us_varqualsave = 0;
45 
46 static WINDOWPART *us_wpop; /* editor window part */
47 static BOOLEAN us_wpopcharhandler(INTSML chr, INTBIG special);
48 static BOOLEAN us_wpopbuttonhandler(INTBIG x, INTBIG y, INTBIG but);
49 
50 /*
51  * Routine to free all memory associated with this module.
52  */
us_freecomtvmemory(void)53 void us_freecomtvmemory(void)
54 {
55 	if (us_varqualsave != 0) efree((CHAR *)us_varqualsave);
56 	if (us_varlimit1 > 0)
57 	{
58 		efree((CHAR *)us_vartype1);
59 		efree((CHAR *)us_varaddr1);
60 	}
61 	if (us_varlimit2 > 0)
62 	{
63 		efree((CHAR *)us_vartype2);
64 		efree((CHAR *)us_varaddr2);
65 	}
66 	if (us_varlimit3 > 0)
67 	{
68 		efree((CHAR *)us_vartype3);
69 		efree((CHAR *)us_varaddr3);
70 	}
71 }
72 
us_technology(INTBIG count,CHAR * par[])73 void us_technology(INTBIG count, CHAR *par[])
74 {
75 	REGISTER INTBIG l, oldlam;
76 	REGISTER CHAR *pp;
77 	CHAR *newpar[3];
78 	extern COMCOMP us_technologyp;
79 	REGISTER TECHNOLOGY *tech, *newtech;
80 	REGISTER NODEPROTO *np, *newnp;
81 	REGISTER NODEINST *ni;
82 	REGISTER WINDOWPART *w;
83 	REGISTER ARCINST *ai;
84 	REGISTER LIBRARY *lib;
85 
86 	/* ensure there is a technology option */
87 	if (count == 0)
88 	{
89 		count = ttygetparam(M_("Technology option: "), &us_technologyp, MAXPARS, par);
90 		if (count == 0)
91 		{
92 			us_abortedmsg();
93 			return;
94 		}
95 	}
96 	l = estrlen(pp = par[0]);
97 
98 	/* handle technology editing */
99 	if (namesamen(pp, x_("edit"), l) == 0)
100 	{
101 		us_tecedentry(count-1, &par[1]);
102 		return;
103 	}
104 
105 	if (namesamen(pp, x_("autoswitch"), l) == 0)
106 	{
107 		if (count < 2)
108 		{
109 			ttyputusage(x_("technology autoswitch on|off"));
110 			return;
111 		}
112 		l = estrlen(pp = par[1]);
113 		if (namesamen(pp, x_("on"), l) == 0 && l >= 2)
114 		{
115 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
116 				us_useroptions | AUTOSWITCHTECHNOLOGY, VINTEGER);
117 			ttyputverbose(M_("Technology will automatically switch to match cell"));
118 			return;
119 		}
120 		if (namesamen(pp, x_("off"), l) == 0 && l >= 2)
121 		{
122 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
123 				us_useroptions & ~AUTOSWITCHTECHNOLOGY, VINTEGER);
124 			ttyputverbose(M_("Automatic technology changing disabled"));
125 			return;
126 		}
127 		ttyputbadusage(x_("technology autoswitch"));
128 		return;
129 	}
130 
131 	/* get the technology */
132 	if (count <= 1)
133 	{
134 		us_abortcommand(_("Must specify a technology name"));
135 		return;
136 	}
137 	tech = gettechnology(par[1]);
138 	if (tech == NOTECHNOLOGY)
139 	{
140 		us_abortcommand(_("No technology called %s"), par[1]);
141 		return;
142 	}
143 
144 	/* handle documentation of technology */
145 	if (namesamen(pp, x_("document"), l) == 0)
146 	{
147 		us_printtechnology(tech);
148 		return;
149 	}
150 
151 	/* handle technology conversion */
152 	if (namesamen(pp, x_("convert"), l) == 0)
153 	{
154 		np = us_needcell();
155 		if (np == NONODEPROTO) return;
156 		newnp = us_convertcell(np, tech);
157 		if (newnp == NONODEPROTO) return;
158 		newpar[0] = describenodeproto(newnp);
159 		newpar[1] = x_("new-window");
160 		us_editcell(2, newpar);
161 		return;
162 	}
163 
164 	/* handle technology switching */
165 	if (namesamen(pp, x_("use"), l) == 0 && l >= 2)
166 	{
167 		if (el_curtech == tech)
168 		{
169 			ttyputverbose(M_("Already in %s technology"), el_curtech->techname);
170 			return;
171 		}
172 
173 		ttyputverbose(M_("Switching to %s"), tech->techdescript);
174 		us_setnodeproto(NONODEPROTO);
175 		us_setarcproto(NOARCPROTO, TRUE);
176 		oldlam = el_curlib->lambda[el_curtech->techindex];
177 		us_getcolormap(tech, COLORSEXISTING, TRUE);
178 		(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_technology_key, (INTBIG)tech,
179 			VTECHNOLOGY|VDONTSAVE);
180 
181 		/* if lambda changed and grid is drawn, erase it */
182 		if (oldlam != el_curlib->lambda[el_curtech->techindex])
183 		{
184 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
185 			{
186 				if ((w->state & GRIDON) == 0) continue;
187 				startobjectchange((INTBIG)w, VWINDOWPART);
188 				us_gridset(w, 0);
189 				endobjectchange((INTBIG)w, VWINDOWPART);
190 				w->state |= GRIDON;
191 			}
192 		}
193 
194 		/* redraw grids */
195 		if (oldlam != el_curlib->lambda[el_curtech->techindex])
196 		{
197 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
198 			{
199 				if ((w->state & GRIDON) == 0) continue;
200 				w->state &= ~GRIDON;
201 				startobjectchange((INTBIG)w, VWINDOWPART);
202 				us_gridset(w, GRIDON);
203 				endobjectchange((INTBIG)w, VWINDOWPART);
204 			}
205 		}
206 
207 		/* fix up the menu entries */
208 		us_setmenunodearcs();
209 		if ((us_state&NONPERSISTENTCURNODE) == 0) us_setnodeproto(tech->firstnodeproto);
210 		us_setarcproto(tech->firstarcproto, TRUE);
211 		return;
212 	}
213 
214 	/* handle technology deletion */
215 	if (namesamen(pp, x_("kill"), l) == 0)
216 	{
217 		/* make sure there are no objects from this technology */
218 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
219 		{
220 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
221 			{
222 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
223 					if (ni->proto->primindex != 0 && ni->proto->tech == tech) break;
224 				if (ni != NONODEINST) break;
225 				for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
226 					if (ai->proto->tech == tech) break;
227 				if (ai != NOARCINST) break;
228 			}
229 			if (np != NONODEPROTO)
230 			{
231 				us_abortcommand(_("Technology %s is still in use"), tech->techname);
232 				return;
233 			}
234 		}
235 
236 		/* cannot delete generic technology */
237 		if (tech == gen_tech)
238 		{
239 			us_abortcommand(_("Cannot delete the generic technology"));
240 			return;
241 		}
242 
243 		/* switch technologies if killing current one */
244 		if (tech == el_curtech)
245 		{
246 			newtech = tech->nexttechnology;
247 			if (newtech == NOTECHNOLOGY)
248 			{
249 				newtech = el_technologies;
250 				if (newtech == tech)
251 				{
252 					us_abortcommand(_("Cannot delete the last technology"));
253 					return;
254 				}
255 			}
256 			ttyputmsg(_("Switching to %s"), newtech->techdescript);
257 			us_setnodeproto(NONODEPROTO);
258 			us_setarcproto(NOARCPROTO, TRUE);
259 			us_getcolormap(newtech, COLORSEXISTING, TRUE);
260 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_current_technology_key,
261 				(INTBIG)newtech, VTECHNOLOGY|VDONTSAVE);
262 
263 			/* fix up the menu entries */
264 			us_setmenunodearcs();
265 			if ((us_state&NONPERSISTENTCURNODE) == 0) us_setnodeproto(newtech->firstnodeproto);
266 			us_setarcproto(newtech->firstarcproto, TRUE);
267 		}
268 		if (killtechnology(tech))
269 			ttyputerr(_("Unable to delete technology %s"), tech->techname);
270 		return;
271 	}
272 
273 	/* handle technology information setting */
274 	if (namesamen(pp, x_("tell"), l) == 0)
275 	{
276 		if (tech->setmode != 0)
277 			telltech(tech, count-2, &par[2]); else
278 				ttyputerr(_("This technology accepts no commands"));
279 		return;
280 	}
281 	ttyputbadusage(x_("technology"));
282 }
283 
us_telltool(INTBIG count,CHAR * par[])284 void us_telltool(INTBIG count, CHAR *par[])
285 {
286 	extern COMCOMP us_telltoolp;
287 	REGISTER TOOL *tool;
288 
289 	if (count == 0)
290 	{
291 		count = ttygetparam(M_("Which tool: "), &us_telltoolp, MAXPARS, par);
292 		if (count == 0)
293 		{
294 			us_abortedmsg();
295 			return;
296 		}
297 	}
298 	tool = gettool(par[0]);
299 	if (tool == NOTOOL)
300 	{
301 		us_abortcommand(_("No tool called %s"), par[0]);
302 		return;
303 	}
304 	if (tool->setmode == 0)
305 	{
306 		us_abortcommand(_("Tool %s cannot take commands"), tool->toolname);
307 		return;
308 	}
309 	(*tool->setmode)(count-1, &par[1]);
310 }
311 
us_terminal(INTBIG count,CHAR * par[])312 void us_terminal(INTBIG count, CHAR *par[])
313 {
314 	REGISTER INTBIG l, forcealpha;
315 	REGISTER CHAR *pt, *pp;
316 	REGISTER VARIABLE *err;
317 	REGISTER CHAR *varname;
318 	INTBIG top, left, bottom, right;
319 	INTBIG msgcoord[4];
320 	CHAR *truename;
321 	REGISTER COMCOMP *comcomp;
322 	float newfloat;
323 	extern COMCOMP us_libraryup,
324 		us_colorreadp, us_helpp, us_technologyup, us_technologyeenp, us_viewfp,
325 		us_technologyeeap, us_technologyeelp, us_arrayxp, us_colorentryp, us_viewc2p,
326 		us_purelayerp, us_defnodesp, us_editcellp, us_spreaddp, us_portlp,
327 		us_defnodexsp, us_lambdachp, us_replacep, us_showp, us_viewn1p, us_showop,
328 		us_copycellp, us_gridalip, us_defarcsp, us_portep, us_visiblelayersp,
329 		us_menup, us_colorpvaluep, us_artlookp, us_colorwritep, us_librarywp,
330 		us_varvep, us_nodetp, us_technologyedlp, us_librarydp, us_technologyctdp,
331 		us_textdsp, us_noyesp, us_librarywriteformatp, us_windowrnamep, us_defnodep,
332 		us_showdp, us_renameop, us_renamenp, us_findnamep, us_varbs1p, us_findintp,
333 		us_colorhighp, us_bindgkeyp, us_gridp, us_technologytp, us_nodetcaip,
334 		us_librarykp, us_findobjap, us_window3dp, us_nodetptlp, us_renamecp,
335 		us_findexportp, us_findnnamep, us_showup, us_varop, us_copycelldp,
336 		us_findnodep, us_technologycnnp, us_showep, us_textfp, us_textsp, us_viewdp,
337 		us_interpretcp, us_findarcp, us_varvmp, us_showrp, us_varbdp, us_portcp,
338 		us_showfp, us_librarynp, us_viewc1p, us_libraryrp, us_defnodenotp,
339 		us_nodetptmp;
340 
341 	if (count == 0)
342 	{
343 		ttyputusage(x_("terminal OPTIONS"));
344 		return;
345 	}
346 	l = estrlen(pp = par[0]);
347 
348 	if (namesamen(pp, x_("not"), l) == 0)
349 	{
350 		if (count < 2)
351 		{
352 			ttyputusage(x_("terminal not OPTION"));
353 			return;
354 		}
355 		l = estrlen(pp = par[1]);
356 		if (namesame(pp, x_("lock-keys-on-error")) == 0)
357 		{
358 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | NOKEYLOCK, VINTEGER);
359 			ttyputverbose(M_("Command errors will not lockout single-key commands"));
360 			return;
361 		}
362 		if (namesame(pp, x_("only-informative-messages")) == 0)
363 		{
364 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~JUSTTHEFACTS, VINTEGER);
365 			ttyputverbose(M_("All messages will be displayed"));
366 			return;
367 		}
368 		if (namesame(pp, x_("use-electric-commands")) == 0)
369 		{
370 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | NODETAILS, VINTEGER);
371 			ttyputverbose(M_("Messages will not mention specific commands"));
372 			return;
373 		}
374 		if (namesame(pp, x_("display-dialogs")) == 0)
375 		{
376 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~USEDIALOGS, VINTEGER);
377 			ttyputverbose(M_("Dialogs will not be used"));
378 			return;
379 		}
380 		if (namesame(pp, x_("permanent-menu-highlighting")) == 0)
381 		{
382 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | ONESHOTMENU, VINTEGER);
383 			ttyputverbose(M_("Menu highlighting will clear after each command"));
384 			return;
385 		}
386 		if (namesame(pp, x_("track-cursor-coordinates")) == 0)
387 		{
388 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~SHOWXY, VINTEGER);
389 			ttyputverbose(M_("Technology and Lambda will be displayed where cursor coordinates are"));
390 			us_redostatus(NOWINDOWFRAME);
391 			return;
392 		}
393 		if (namesame(pp, x_("beep")) == 0)
394 		{
395 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~TERMBEEP, VINTEGER);
396 			ttyputverbose(M_("Terminal beep disabled"));
397 			return;
398 		}
399 		if (namesamen(pp, x_("enable-interrupts"), l) == 0)
400 		{
401 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | TERMNOINTERRUPT, VINTEGER);
402 			ttyputmsg(M_("Interrupts disabled"));
403 			return;
404 		}
405 		if (namesamen(pp, x_("audit"), l) == 0)
406 		{
407 			if (us_termaudit != NULL) xclose(us_termaudit);
408 			us_termaudit = NULL;
409 			(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~TTYAUDIT, VINTEGER);
410 			ttyputverbose(M_("No longer saving messages"));
411 			return;
412 		}
413 		ttyputbadusage(x_("terminal not"));
414 		return;
415 	}
416 
417 	if (namesamen(pp, x_("clear"), l) == 0)
418 	{
419 		ttyclearmessages();
420 		return;
421 	}
422 
423 	if (namesamen(pp, x_("get-location"), l) == 0)
424 	{
425 		getmessagesframeinfo(&top, &left, &bottom, &right);
426 		msgcoord[0] = top;
427 		msgcoord[1] = left;
428 		msgcoord[2] = bottom;
429 		msgcoord[3] = right;
430 		(void)setval((INTBIG)us_tool, VTOOL, x_("USER_messages_position"),
431 			(INTBIG)msgcoord, VINTEGER|VISARRAY|(4<<VLENGTHSH));
432 		ttyputmsg(_("Window location will be saved with the options"));
433 		return;
434 	}
435 
436 	if (namesamen(pp, x_("lock-keys-on-error"), l) == 0 && l >= 2)
437 	{
438 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~NOKEYLOCK, VINTEGER);
439 		ttyputverbose(M_("Command errors will lockout single-key commands"));
440 		return;
441 	}
442 
443 	if (namesamen(pp, x_("only-informative-messages"), l) == 0)
444 	{
445 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | JUSTTHEFACTS, VINTEGER);
446 		ttyputverbose(M_("Nonessential messages will be supressed"));
447 		return;
448 	}
449 
450 	if (namesamen(pp, x_("display-dialogs"), l) == 0)
451 	{
452 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | USEDIALOGS, VINTEGER);
453 		ttyputverbose(M_("Dialogs will be use where appropriate"));
454 		return;
455 	}
456 
457 	if (namesamen(pp, x_("permanent-menu-highlighting"), l) == 0)
458 	{
459 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~ONESHOTMENU, VINTEGER);
460 		ttyputverbose(M_("Menu highlighting will show current node/arc"));
461 		return;
462 	}
463 
464 	if (namesame(pp, x_("track-cursor-coordinates")) == 0)
465 	{
466 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | SHOWXY, VINTEGER);
467 		ttyputverbose(M_("Cursor coordinates will be displayed where TECH/LAMBDA are"));
468 		us_redostatus(NOWINDOWFRAME);
469 		return;
470 	}
471 	if (namesamen(pp, x_("use-electric-commands"), l) == 0)
472 	{
473 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~NODETAILS, VINTEGER);
474 		ttyputverbose(M_("Messages will use specific Electric commands"));
475 		return;
476 	}
477 	if (namesamen(pp, x_("beep"), l) == 0)
478 	{
479 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | TERMBEEP, VINTEGER);
480 		ttyputverbose(M_("Terminal beep enabled"));
481 		return;
482 	}
483 	if (namesamen(pp, x_("enable-interrupts"), l) == 0)
484 	{
485 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~TERMNOINTERRUPT, VINTEGER);
486 		ttyputmsg(M_("Interrupts enabled"));
487 		return;
488 	}
489 	if (namesamen(pp, x_("audit"), l) == 0)
490 	{
491 		us_termaudit = xcreate(x_("emessages.txt"), el_filetypetext, 0, &truename);
492 		if (us_termaudit == 0)
493 		{
494 			ttyputerr(_("Cannot create 'emessages.txt'"));
495 			return;
496 		}
497 		ttyputmsg(_("Saving messages to '%s'"), truename);
498 		(void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate | TTYAUDIT, VINTEGER);
499 		return;
500 	}
501 
502 	if (namesamen(pp, x_("input"), l) == 0)
503 	{
504 		/* make sure there are the right number of parameters */
505 		if (count < 3)
506 		{
507 			ttyputusage(x_("terminal input LETTER PROMPT [TYPE]"));
508 			return;
509 		}
510 
511 		/* make sure the command interpreter variable is a single letter */
512 		if (!isalpha(par[1][0]) != 0 || par[1][1] != 0)
513 		{
514 			us_abortcommand(_("Input value must be a single letter"));
515 			return;
516 		}
517 		varname = us_commandvarname(par[1][0]);
518 
519 		/* get the value */
520 		forcealpha = 0;
521 		if (count == 4 && namesame(par[3], x_("string")) == 0)
522 		{
523 			count--;
524 			forcealpha = 1;
525 		}
526 		if (count < 4)
527 		{
528 			pt = ttygetline(par[2]);
529 			if (pt == 0) pt = x_("");
530 		} else
531 		{
532 			forcealpha = 1;
533 			comcomp = NOCOMCOMP;
534 
535 			if (namesame(par[3], x_("about")) == 0)         comcomp = &us_showep; else
536 			if (namesame(par[3], x_("alignment")) == 0)     comcomp = &us_gridalip; else
537 			if (namesame(par[3], x_("annulus")) == 0)       comcomp = &us_nodetcaip; else
538 			if (namesame(par[3], x_("array")) == 0)         comcomp = &us_arrayxp; else
539 			if (namesame(par[3], x_("artlook")) == 0)       comcomp = &us_artlookp; else
540 			if (namesame(par[3], x_("attreport")) == 0)     comcomp = &us_varbs1p; else
541 			if (namesame(par[3], x_("attributes")) == 0)    comcomp = &us_varop; else
542 			if (namesame(par[3], x_("attparam")) == 0)      comcomp = &us_varbdp; else
543 			if (namesame(par[3], x_("change")) == 0)        comcomp = &us_replacep; else
544 			if (namesame(par[3], x_("chglibrary")) == 0)    comcomp = &us_librarykp; else
545 			if (namesame(par[3], x_("copycell")) == 0)      comcomp = &us_copycellp; else
546 			if (namesame(par[3], x_("copyrightopt")) == 0)  comcomp = &us_defnodenotp; else
547 			if (namesame(par[3], x_("defarc")) == 0)        comcomp = &us_defarcsp; else
548 			if (namesame(par[3], x_("defnode")) == 0)       comcomp = &us_defnodexsp; else
549 			if (namesame(par[3], x_("deftext")) == 0)       comcomp = &us_textdsp; else
550 			if (namesame(par[3], x_("delcell")) == 0)       comcomp = &us_showup; else
551 			if (namesame(par[3], x_("delview")) == 0)       comcomp = &us_viewdp; else
552 			if (namesame(par[3], x_("dependentlibs")) == 0) comcomp = &us_technologyedlp; else
553 			if (namesame(par[3], x_("depth3d")) == 0)       comcomp = &us_window3dp; else
554 			if (namesame(par[3], x_("editcell")) == 0)      comcomp = &us_editcellp; else
555 			if (namesame(par[3], x_("edtecarc")) == 0)      comcomp = &us_technologyeeap; else
556 			if (namesame(par[3], x_("edteclayer")) == 0)    comcomp = &us_technologyeelp; else
557 			if (namesame(par[3], x_("edtecnode")) == 0)     comcomp = &us_technologyeenp; else
558 			if (namesame(par[3], x_("enumattrs")) == 0)     comcomp = &us_varvmp; else
559 			if (namesame(par[3], x_("cellinfo")) == 0)      comcomp = &us_defnodep; else
560 			if (namesame(par[3], x_("celllist")) == 0)      comcomp = &us_showfp; else
561 			if (namesame(par[3], x_("cellinst")) == 0)      comcomp = &us_viewc1p; else
562 			if (namesame(par[3], x_("cell")) == 0)          comcomp = &us_showdp; else
563 			if (namesame(par[3], x_("file")) == 0)          comcomp = &us_colorreadp; else
564 			if (namesame(par[3], x_("find")) == 0)          comcomp = &us_textfp; else
565 			if (namesame(par[3], x_("frameopt")) == 0)      comcomp = &us_viewfp; else
566 			if (namesame(par[3], x_("genopt")) == 0)        comcomp = &us_showrp; else
567 			if (namesame(par[3], x_("globsignal")) == 0)    comcomp = &us_portcp; else
568 			if (namesame(par[3], x_("grid")) == 0)          comcomp = &us_gridp; else
569 			if (namesame(par[3], x_("help")) == 0)          comcomp = &us_helpp; else
570 			if (namesame(par[3], x_("highlayer")) == 0)     comcomp = &us_colorhighp; else
571 			if (namesame(par[3], x_("iconopt")) == 0)       comcomp = &us_copycelldp; else
572 			if (namesame(par[3], x_("javaopt")) == 0)       comcomp = &us_interpretcp; else
573 			if (namesame(par[3], x_("labels")) == 0)        comcomp = &us_portlp; else
574 			if (namesame(par[3], x_("lambda")) == 0)        comcomp = &us_lambdachp; else
575 			if (namesame(par[3], x_("layerpatterns")) == 0) comcomp = &us_colorpvaluep; else
576 			if (namesame(par[3], x_("layers")) == 0)        comcomp = &us_colorentryp; else
577 			if (namesame(par[3], x_("library")) == 0)       comcomp = &us_libraryup; else
578 			if (namesame(par[3], x_("libtotech")) == 0)     comcomp = &us_technologycnnp; else
579 			if (namesame(par[3], x_("menu")) == 0)          comcomp = &us_menup; else
580 			if (namesame(par[3], x_("newview")) == 0)       comcomp = &us_viewn1p; else
581 			if (namesame(par[3], x_("node")) == 0)          comcomp = &us_defnodesp; else
582 			if (namesame(par[3], x_("noyes")) == 0)         comcomp = &us_noyesp; else
583 			if (namesame(par[3], x_("ofile")) == 0)         comcomp = &us_colorwritep; else
584 			if (namesame(par[3], x_("optionexamine")) == 0) comcomp = &us_librarynp; else
585 			if (namesame(par[3], x_("optionfind")) == 0)    comcomp = &us_libraryrp; else
586 			if (namesame(par[3], x_("optionsave")) == 0)    comcomp = &us_librarywp; else
587 			if (namesame(par[3], x_("path")) == 0)          comcomp = &us_librarydp; else
588 			if (namesame(par[3], x_("placetext")) == 0)     comcomp = &us_nodetptlp; else
589 			if (namesame(par[3], x_("plot")) == 0)          comcomp = &us_librarywriteformatp; else
590 			if (namesame(par[3], x_("port")) == 0)          comcomp = &us_portep; else
591 			if (namesame(par[3], x_("purelayer")) == 0)     comcomp = &us_purelayerp; else
592 			if (namesame(par[3], x_("quickkey")) == 0)      comcomp = &us_bindgkeyp; else
593 			if (namesame(par[3], x_("renameexport")) == 0)  comcomp = &us_renamecp; else
594 			if (namesame(par[3], x_("renamelib")) == 0)     comcomp = &us_renameop; else
595 			if (namesame(par[3], x_("renametech")) == 0)    comcomp = &us_renamenp; else
596 			if (namesame(par[3], x_("renamecell")) == 0)    comcomp = &us_findnamep; else
597 			if (namesame(par[3], x_("renamenet")) == 0)     comcomp = &us_findintp; else
598 			if (namesame(par[3], x_("romgen")) == 0)        comcomp = &us_nodetptmp; else
599 			if (namesame(par[3], x_("selectarc")) == 0)     comcomp = &us_findarcp; else
600 			if (namesame(par[3], x_("selectnet")) == 0)     comcomp = &us_findnnamep; else
601 			if (namesame(par[3], x_("selectnode")) == 0)    comcomp = &us_findnodep; else
602 			if (namesame(par[3], x_("selectopt")) == 0)     comcomp = &us_findobjap; else
603 			if (namesame(par[3], x_("selectport")) == 0)    comcomp = &us_findexportp; else
604 			if (namesame(par[3], x_("showdetail")) == 0)    comcomp = &us_showop; else
605 			if (namesame(par[3], x_("show")) == 0)          comcomp = &us_showp; else
606 			if (namesame(par[3], x_("spread")) == 0)        comcomp = &us_spreaddp; else
607 			if (namesame(par[3], x_("technology")) == 0)    comcomp = &us_technologyup; else
608 			if (namesame(par[3], x_("techopt")) == 0)       comcomp = &us_technologytp; else
609 			if (namesame(par[3], x_("techvars")) == 0)      comcomp = &us_technologyctdp; else
610 			if (namesame(par[3], x_("textsize")) == 0)      comcomp = &us_textsp; else
611 			if (namesame(par[3], x_("trace")) == 0)         comcomp = &us_nodetp; else
612 			if (namesame(par[3], x_("variable")) == 0)      comcomp = &us_varvep; else
613 			if (namesame(par[3], x_("view")) == 0)          comcomp = &us_viewc2p; else
614 			if (namesame(par[3], x_("visiblelayers")) == 0) comcomp = &us_visiblelayersp; else
615 			if (namesame(par[3], x_("windowview")) == 0)    comcomp = &us_windowrnamep; else
616 				comcomp = us_getcomcompfromkeyword(par[3]);
617 			if (comcomp == NOCOMCOMP)
618 			{
619 				us_abortcommand(_("Unknown input type: %s"), par[3]);
620 				return;
621 			}
622 			count = ttygetparam(par[2], comcomp, MAXPARS-3, &par[3]);
623 			if (count < 1) pt = x_(""); else pt = par[3];
624 		}
625 		if (*pt == 0)
626 		{
627 			if (getval((INTBIG)us_tool, VTOOL, -1, varname) != NOVARIABLE)
628 				(void)delval((INTBIG)us_tool, VTOOL, varname);
629 			return;
630 		}
631 
632 		/* store the value */
633 		if (isanumber(pt) && forcealpha == 0)
634 		{
635 			for(pp = pt; *pp != 0; pp++) if (*pp == '.')
636 			{
637 				newfloat = (float)eatof(pt);
638 				err = setval((INTBIG)us_tool, VTOOL, varname, castint(newfloat), VFLOAT|VDONTSAVE);
639 				break;
640 			}
641 			if (*pp == 0)
642 				err = setval((INTBIG)us_tool, VTOOL, varname, myatoi(pt), VINTEGER|VDONTSAVE);
643 		} else err = setval((INTBIG)us_tool, VTOOL, varname, (INTBIG)pt, VSTRING|VDONTSAVE);
644 		if (err == NOVARIABLE)
645 		{
646 			us_abortcommand(_("Problem setting variable %s"), par[1]);
647 			return;
648 		}
649 		return;
650 	}
651 
652 	if (namesamen(pp, x_("session"), l) == 0)
653 	{
654 		if (!graphicshas(CANLOGINPUT))
655 		{
656 			us_abortcommand(_("Sorry, this display driver does not log sessions"));
657 			return;
658 		}
659 
660 		/* make sure there are the right number of parameters */
661 		if (count <= 1) l = estrlen(pp = x_("?")); else
662 			l = estrlen(pp = par[1]);
663 
664 		if (namesamen(pp, x_("playback"), l) == 0)
665 		{
666 			if (count <= 2)
667 			{
668 				ttyputusage(x_("terminal session playback FILE"));
669 				return;
670 			}
671 			if (logplayback(par[2]))
672 				us_abortcommand(_("Cannot read playback file %s"), par[2]);
673 			return;
674 		}
675 
676 		if (namesamen(pp, x_("begin-record"), l) == 0)
677 		{
678 			if (us_logrecord != NULL)
679 			{
680 				us_abortcommand(_("Session is already being recorded"));
681 				return;
682 			}
683 			logstartrecord();
684 			return;
685 		}
686 
687 		/* make sure session logging is on */
688 		if (us_logrecord == NULL)
689 		{
690 			us_abortcommand(_("Session is not being recorded"));
691 			return;
692 		}
693 
694 		if (namesamen(pp, x_("end-record"), l) == 0)
695 		{
696 			logfinishrecord();
697 			return;
698 		}
699 
700 		if (namesamen(pp, x_("rewind-record"), l) == 0)
701 		{
702 			logfinishrecord();
703 			logstartrecord();
704 			return;
705 		}
706 
707 		if (namesamen(pp, x_("checkpoint-frequency"), l) == 0)
708 		{
709 			if (count <= 2)
710 			{
711 				ttyputusage(x_("terminal session checkpoint-frequency F"));
712 				return;
713 			}
714 			us_logflushfreq = myatoi(par[2]);
715 			ttyputverbose(M_("Session logging will be guaranteed every %ld commands"),
716 				us_logflushfreq);
717 			return;
718 		}
719 
720 		ttyputbadusage(x_("terminal session"));
721 		return;
722 	}
723 
724 	ttyputbadusage(x_("terminal"));
725 }
726 
us_text(INTBIG count,CHAR * par[])727 void us_text(INTBIG count, CHAR *par[])
728 {
729 	REGISTER INTBIG grabpoint, newgrabpoint, len, font;
730 	REGISTER INTBIG i, l;
731 	INTBIG xw, yw, xcur, ycur, adjxc, adjyc;
732 	UINTBIG descript[TEXTDESCRIPTSIZE], olddescript[TEXTDESCRIPTSIZE];
733 	INTBIG tsx, tsy, style;
734 	REGISTER CHAR *pp, *str;
735 	REGISTER NODEINST *ni;
736 	REGISTER NODEPROTO *np;
737 	REGISTER VARIABLE *var;
738 	REGISTER WINDOWPART *w;
739 	REGISTER HIGHLIGHT *high;
740 	REGISTER TECHNOLOGY *tech;
741 	static POLYGON *poly = NOPOLYGON;
742 	static CHAR *smartstyle[3] = {N_("off"), N_("inside"), N_("outside")};
743 
744 	/* get polygon */
745 	(void)needstaticpolygon(&poly, 4, us_tool->cluster);
746 
747 	if (count == 0)
748 	{
749 		ttyputusage(x_("text style|size|editor|default-*|read|write"));
750 		return;
751 	}
752 	l = estrlen(pp = par[0]);
753 
754 	/* handle text saving */
755 	if (namesamen(pp, x_("write"), l) == 0 && l >= 1)
756 	{
757 		if (count < 2)
758 		{
759 			ttyputusage(x_("text write FILENAME"));
760 			return;
761 		}
762 
763 		if (us_needwindow()) return;
764 
765 		/* make sure the current window is textual */
766 		if ((el_curwindowpart->state&WINDOWTYPE) != POPTEXTWINDOW &&
767 			(el_curwindowpart->state&WINDOWTYPE) != TEXTWINDOW)
768 		{
769 			us_abortcommand(_("Current window is not textual"));
770 			return;
771 		}
772 
773 		us_writetextfile(el_curwindowpart, par[1]);
774 		return;
775 	}
776 
777 	/* handle text cell reading */
778 	if (namesamen(pp, x_("read"), l) == 0 && l >= 1)
779 	{
780 		if (count < 2)
781 		{
782 			ttyputusage(x_("text read FILENAME"));
783 			return;
784 		}
785 
786 		if (us_needwindow()) return;
787 
788 		/* make sure the current window is textual */
789 		if ((el_curwindowpart->state&WINDOWTYPE) != POPTEXTWINDOW &&
790 			(el_curwindowpart->state&WINDOWTYPE) != TEXTWINDOW)
791 		{
792 			us_abortcommand(_("Current window is not textual"));
793 			return;
794 		}
795 
796 		us_readtextfile(el_curwindowpart, par[1]);
797 		return;
798 	}
799 
800 	/* handle text cell manipulation */
801 	if (namesamen(pp, x_("cut"), l) == 0 && l >= 2)
802 	{
803 		/* first see if this applies to messages window */
804 		if (cutfrommessages()) return;
805 
806 		/* next see if it applies to a text edit window */
807 		if (us_needwindow()) return;
808 		switch (el_curwindowpart->state&WINDOWTYPE)
809 		{
810 			case POPTEXTWINDOW:
811 			case TEXTWINDOW:
812 				us_cuttext(el_curwindowpart);
813 				break;
814 			case DISPWINDOW:
815 				us_cutobjects(el_curwindowpart);
816 				break;
817 			case WAVEFORMWINDOW:
818 				ttyputmsg(_("To copy waveforms, use 'p' to preserve a snapshot"));
819 				break;
820 			case EXPLORERWINDOW:
821 				ttyputmsg(_("You cannot cut from a cell explorer window, but you can copy"));
822 				break;
823 			default:
824 				ttyputmsg(_("Cannot cut from this type of window"));
825 				break;
826 		}
827 		return;
828 	}
829 	if (namesamen(pp, x_("copy"), l) == 0 && l >= 2)
830 	{
831 		/* first see if this applies to messages window */
832 		if (copyfrommessages()) return;
833 
834 		/* next see if it applies to a text edit window */
835 		if (us_needwindow()) return;
836 		switch (el_curwindowpart->state&WINDOWTYPE)
837 		{
838 			case POPTEXTWINDOW:
839 			case TEXTWINDOW:
840 				us_copytext(el_curwindowpart);
841 				break;
842 			case DISPWINDOW:
843 				us_copyobjects(el_curwindowpart);
844 				break;
845 			case WAVEFORMWINDOW:
846 				ttyputmsg(_("To copy waveforms, use 'p' to preserve a snapshot"));
847 				break;
848 			case EXPLORERWINDOW:
849 				us_copyexplorerwindow();
850 				break;
851 			default:
852 				ttyputmsg(_("Cannot copy from this type of window"));
853 				break;
854 		}
855 		return;
856 	}
857 	if (namesamen(pp, x_("paste"), l) == 0 && l >= 1)
858 	{
859 		/* first see if this applies to messages window */
860 		if (pastetomessages()) return;
861 
862 		/* next see if it applies to a text edit window */
863 		if (us_needwindow()) return;
864 		switch (el_curwindowpart->state&WINDOWTYPE)
865 		{
866 			case POPTEXTWINDOW:
867 			case TEXTWINDOW:
868 				us_pastetext(el_curwindowpart);
869 				break;
870 			case DISPWINDOW:
871 				us_pasteobjects(el_curwindowpart);
872 				break;
873 			default:
874 				ttyputmsg(_("Cannot paste to this type of window"));
875 				break;
876 		}
877 		return;
878 	}
879 	if (namesamen(pp, x_("find"), l) == 0 && l >= 1)
880 	{
881 		if (count < 2)
882 		{
883 			ttyputusage(x_("text find STRING"));
884 			return;
885 		}
886 
887 		/* make sure the current window is textual */
888 		if (us_needwindow()) return;
889 		if ((el_curwindowpart->state&WINDOWTYPE) != POPTEXTWINDOW &&
890 			(el_curwindowpart->state&WINDOWTYPE) != TEXTWINDOW)
891 		{
892 			us_abortcommand(_("Current window is not textual"));
893 			return;
894 		}
895 
896 		us_searchtext(el_curwindowpart, par[1], 0, 0);
897 		return;
898 	}
899 
900 	/* handle editor selection */
901 	if (namesamen(pp, x_("editor"), l) == 0 && l >= 2)
902 	{
903 		if (count < 2)
904 		{
905 			ttyputmsg(_("Current text editor is %s"), us_editortable[us_currenteditor].editorname);
906 			return;
907 		}
908 		l = estrlen(pp = par[1]);
909 
910 		/* make sure there are no text editors running */
911 		for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
912 			if ((w->state&WINDOWTYPE) == TEXTWINDOW || (w->state&WINDOWTYPE) == POPTEXTWINDOW)
913 		{
914 			us_abortcommand(_("Must terminate all active editors before switching"));
915 			return;
916 		}
917 
918 		for(i=0; us_editortable[i].editorname != 0; i++)
919 			if (namesamen(pp, us_editortable[i].editorname, l) == 0) break;
920 		if (us_editortable[i].editorname == 0)
921 		{
922 			us_abortcommand(_("Unknown editor: %s"), pp);
923 			return;
924 		}
925 		ttyputverbose(M_("Now using %s editor for text"), us_editortable[i].editorname);
926 		setvalkey((INTBIG)us_tool, VTOOL, us_text_editorkey, (INTBIG)us_editortable[i].editorname,
927 			VSTRING);
928 		return;
929 	}
930 
931 	if (namesamen(pp, x_("easy-text-selection"), l) == 0 && l >= 2)
932 	{
933 		if ((us_useroptions&NOTEXTSELECT) == 0)
934 			ttyputverbose(M_("Annotation text is already easy to select")); else
935 		{
936 			ttyputverbose(M_("Annotation text will be easily selectable"));
937 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
938 				us_useroptions | NOTEXTSELECT, VINTEGER);
939 		}
940 		return;
941 	}
942 
943 	if (namesamen(pp, x_("hard-text-selection"), l) == 0 && l >= 1)
944 	{
945 		if ((us_useroptions&NOTEXTSELECT) != 0)
946 			ttyputverbose(M_("Annotation text is already hard to select")); else
947 		{
948 			ttyputverbose(M_("Annotation text will be hard to select (only when the 'find' command does NOT have the 'port' option)"));
949 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
950 				us_useroptions & ~NOTEXTSELECT, VINTEGER);
951 		}
952 		return;
953 	}
954 
955 	/* handle default node text size */
956 	if (namesamen(pp, x_("default-node-size"), l) == 0 && l >= 9)
957 	{
958 		/* get new value */
959 		if (count < 2)
960 		{
961 			ttyputusage(x_("text default-node-size SIZE"));
962 			return;
963 		}
964 		defaulttextsize(3, descript);
965 		font = us_gettextsize(par[1], TDGETSIZE(descript));
966 		if (font < 0) return;
967 		TDSETSIZE(descript, font);
968 
969 		/* set the default text size */
970 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_node_text_size"),
971 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
972 		ttyputverbose(M_("Default node text size is now %s"), us_describefont(font));
973 		return;
974 	}
975 
976 	/* handle default arc text size */
977 	if (namesamen(pp, x_("default-arc-size"), l) == 0 && l >= 9)
978 	{
979 		/* get new value */
980 		if (count < 2)
981 		{
982 			ttyputusage(x_("text default-arc-size SIZE"));
983 			return;
984 		}
985 		defaulttextsize(4, descript);
986 		font = us_gettextsize(par[1], TDGETSIZE(descript));
987 		if (font < 0) return;
988 		TDSETSIZE(descript, font);
989 
990 		/* set the default text size */
991 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_arc_text_size"),
992 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
993 		ttyputverbose(M_("Default arc text size is now %s"), us_describefont(font));
994 		return;
995 	}
996 
997 	/* handle default export text size */
998 	if (namesamen(pp, x_("default-export-size"), l) == 0 && l >= 11)
999 	{
1000 		/* get new value */
1001 		if (count < 2)
1002 		{
1003 			ttyputusage(x_("text default-export-size SIZE"));
1004 			return;
1005 		}
1006 		defaulttextsize(1, descript);
1007 		font = us_gettextsize(par[1], TDGETSIZE(descript));
1008 		if (font < 0) return;
1009 		TDSETSIZE(descript, font);
1010 
1011 		/* set the default text size */
1012 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_export_text_size"),
1013 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
1014 		ttyputverbose(M_("Default export text size is now %s"), us_describefont(font));
1015 		return;
1016 	}
1017 
1018 	/* handle default nonlayout text size */
1019 	if (namesamen(pp, x_("default-nonlayout-text-size"), l) == 0 && l >= 9)
1020 	{
1021 		/* get new value */
1022 		if (count < 2)
1023 		{
1024 			ttyputusage(x_("text default-nonlayout-text-size SIZE"));
1025 			return;
1026 		}
1027 		defaulttextsize(2, descript);
1028 		font = us_gettextsize(par[1], TDGETSIZE(descript));
1029 		if (font < 0) return;
1030 		TDSETSIZE(descript, font);
1031 
1032 		/* set the default text size */
1033 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_nonlayout_text_size"),
1034 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
1035 		ttyputverbose(M_("Default nonlayout text size is now %s"), us_describefont(font));
1036 		return;
1037 	}
1038 
1039 	/* handle default instance name size */
1040 	if (namesamen(pp, x_("default-instance-size"), l) == 0 && l >= 9)
1041 	{
1042 		/* get new value */
1043 		if (count < 2)
1044 		{
1045 			ttyputusage(x_("text default-instance-size SIZE"));
1046 			return;
1047 		}
1048 		defaulttextsize(5, descript);
1049 		font = us_gettextsize(par[1], TDGETSIZE(descript));
1050 		if (font < 0) return;
1051 		TDSETSIZE(descript, font);
1052 
1053 		/* set the default text size */
1054 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_instance_text_size"),
1055 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
1056 		ttyputverbose(M_("Default instance text size is now %s"), us_describefont(font));
1057 		return;
1058 	}
1059 
1060 	/* handle default cell text size */
1061 	if (namesamen(pp, x_("default-cell-size"), l) == 0 && l >= 9)
1062 	{
1063 		/* get new value */
1064 		if (count < 2)
1065 		{
1066 			ttyputusage(x_("text default-cell-size SIZE"));
1067 			return;
1068 		}
1069 		defaulttextsize(6, descript);
1070 		font = us_gettextsize(par[1], TDGETSIZE(descript));
1071 		if (font < 0) return;
1072 		TDSETSIZE(descript, font);
1073 
1074 		/* set the default text size */
1075 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_facet_text_size"),
1076 			(INTBIG)descript, VINTEGER|VISARRAY|(TEXTDESCRIPTSIZE<<VLENGTHSH)|VDONTSAVE);
1077 		ttyputverbose(M_("Default cell text size is now %s"), us_describefont(font));
1078 		return;
1079 	}
1080 
1081 	/* handle default interior style */
1082 	if (namesamen(pp, x_("default-interior-only"), l) == 0 && l >= 9)
1083 	{
1084 		/* get current value */
1085 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_default_text_style"));
1086 		if (var == NOVARIABLE) grabpoint = VTPOSCENT; else grabpoint = var->addr;
1087 
1088 		/* set the default interior style */
1089 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_text_style"),
1090 			grabpoint|VTINTERIOR, VINTEGER|VDONTSAVE);
1091 		ttyputverbose(M_("Default text is visible only inside cell"));
1092 		return;
1093 	}
1094 	if (namesamen(pp, x_("default-exterior"), l) == 0 && l >= 11)
1095 	{
1096 		/* get current value */
1097 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_default_text_style"));
1098 		if (var == NOVARIABLE) grabpoint = VTPOSCENT; else grabpoint = var->addr;
1099 
1100 		/* set the default interior style */
1101 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_text_style"),
1102 			grabpoint & ~VTINTERIOR, VINTEGER|VDONTSAVE);
1103 		ttyputverbose(M_("Default text is visible outside of cell"));
1104 		return;
1105 	}
1106 
1107 	/* handle default style */
1108 	if (namesamen(pp, x_("default-style"), l) == 0 && l >= 9)
1109 	{
1110 		/* get current value */
1111 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_default_text_style"));
1112 		if (var == NOVARIABLE) grabpoint = VTPOSCENT; else grabpoint = var->addr;
1113 
1114 		/* if no argument provided, show current value */
1115 		if (count < 2)
1116 		{
1117 			ttyputmsg(M_("Default text style is %s"), us_describestyle(grabpoint));
1118 			if ((grabpoint&VTINTERIOR) != 0)
1119 				ttyputmsg(M_("Default text is visible only inside cell")); else
1120 					ttyputmsg(M_("Default text is visible outside of cell"));
1121 			return;
1122 		}
1123 
1124 		/* get new value */
1125 		newgrabpoint = us_gettextposition(par[1]);
1126 		grabpoint = (grabpoint & ~VTPOSITION) | newgrabpoint;
1127 
1128 		/* set the default text style */
1129 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_text_style"),
1130 			grabpoint, VINTEGER|VDONTSAVE);
1131 		ttyputverbose(M_("Default text style is now %s"), us_describestyle(grabpoint));
1132 		return;
1133 	}
1134 
1135 	/* handle default horizontal and vertical style */
1136 	if (namesamen(pp, x_("default-horizontal-style"), l) == 0 && l >= 9)
1137 	{
1138 		/* get current value */
1139 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_default_text_smart_style"));
1140 		if (var == NOVARIABLE) grabpoint = 0; else grabpoint = var->addr;
1141 
1142 		/* if no argument provided, show current value */
1143 		if (count < 2)
1144 		{
1145 			ttyputmsg(M_("Default horizontal text style is %s"),
1146 				TRANSLATE(smartstyle[grabpoint&03]));
1147 			return;
1148 		}
1149 
1150 		/* get new value */
1151 		l = estrlen(pp = par[1]);
1152 		if (namesamen(pp, x_("none"), l) == 0) grabpoint = (grabpoint & ~03) | 0; else
1153 		if (namesamen(pp, x_("inside"), l) == 0) grabpoint = (grabpoint & ~03) | 1; else
1154 		if (namesamen(pp, x_("outside"), l) == 0) grabpoint = (grabpoint & ~03) | 2; else
1155 		{
1156 			ttyputusage(x_("text default-horizontal-style [none|inside|outside]"));
1157 			return;
1158 		}
1159 
1160 		/* set the default text style */
1161 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_text_smart_style"), grabpoint, VINTEGER|VDONTSAVE);
1162 		ttyputverbose(M_("Default horizontal text style is now %s"), TRANSLATE(smartstyle[grabpoint&03]));
1163 		return;
1164 	}
1165 	if (namesamen(pp, x_("default-vertical-style"), l) == 0 && l >= 9)
1166 	{
1167 		/* get current value */
1168 		var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_default_text_smart_style"));
1169 		if (var == NOVARIABLE) grabpoint = 0; else grabpoint = var->addr;
1170 
1171 		/* if no argument provided, show current value */
1172 		if (count < 2)
1173 		{
1174 			ttyputmsg(M_("Default vertical text style is %s"),
1175 				TRANSLATE(smartstyle[(grabpoint>>2)&03]));
1176 			return;
1177 		}
1178 
1179 		/* get new value */
1180 		l = estrlen(pp = par[1]);
1181 		if (namesamen(pp, x_("none"), l) == 0) grabpoint = (grabpoint & ~014) | 0; else
1182 		if (namesamen(pp, x_("inside"), l) == 0) grabpoint = (grabpoint & ~014) | (1<<2); else
1183 		if (namesamen(pp, x_("outside"), l) == 0) grabpoint = (grabpoint & ~014) | (2<<2); else
1184 		{
1185 			ttyputusage(x_("text default-vertical-style [none|inside|outside]"));
1186 			return;
1187 		}
1188 
1189 		/* set the default text style */
1190 		setval((INTBIG)us_tool, VTOOL, x_("USER_default_text_smart_style"), grabpoint, VINTEGER|VDONTSAVE);
1191 		ttyputverbose(M_("Default vertical text style is now %s"), TRANSLATE(smartstyle[(grabpoint>>2)&03]));
1192 		return;
1193 	}
1194 
1195 	/* get the text object */
1196 	high = us_getonehighlight();
1197 	if (high == NOHIGHLIGHT) return;
1198 	if ((high->status&HIGHTYPE) != HIGHTEXT)
1199 	{
1200 		us_abortcommand(_("Find a single text object first"));
1201 		return;
1202 	}
1203 
1204 	/* handle grab-point motion */
1205 	if (namesamen(pp, x_("style"), l) == 0 && l >= 2)
1206 	{
1207 		/* make sure the cursor is in the right cell */
1208 		np = us_needcell();
1209 		if (np == NONODEPROTO) return;
1210 		if (np != high->cell)
1211 		{
1212 			us_abortcommand(_("Must have cursor in this cell"));
1213 			return;
1214 		}
1215 
1216 		/* get the center of the text */
1217 		us_gethightextcenter(high, &adjxc, &adjyc, &style);
1218 
1219 		/* get the text and current descriptor */
1220 		str = us_gethighstring(high);
1221 		us_gethighdescript(high, olddescript);
1222 
1223 		/* get size of text */
1224 		len = 1;
1225 		if (high->fromvar != NOVARIABLE && (high->fromvar->type&VISARRAY) != 0)
1226 			len = getlength(high->fromvar);
1227 		if (len > 1)
1228 		{
1229 			xw = high->fromgeom->highx - high->fromgeom->lowx;
1230 			yw = high->fromgeom->highy - high->fromgeom->lowy;
1231 		} else
1232 		{
1233 			if (!high->fromgeom->entryisnode)
1234 				tech = high->fromgeom->entryaddr.ai->proto->tech; else
1235 					tech = high->fromgeom->entryaddr.ni->proto->tech;
1236 			screensettextinfo(el_curwindowpart, tech, olddescript);
1237 			screengettextsize(el_curwindowpart, str, &tsx, &tsy);
1238 			xw = muldiv(tsx, el_curwindowpart->screenhx-el_curwindowpart->screenlx,
1239 				el_curwindowpart->usehx-el_curwindowpart->uselx);
1240 			yw = muldiv(tsy, el_curwindowpart->screenhy-el_curwindowpart->screenly,
1241 				el_curwindowpart->usehy-el_curwindowpart->usely);
1242 		}
1243 
1244 		/* save highlighting */
1245 		us_pushhighlight();
1246 		us_clearhighlightcount();
1247 
1248 		/* see if a specific grab point has been mentioned */
1249 		if (count >= 2)
1250 		{
1251 			grabpoint = us_gettextposition(par[1]);
1252 			TDCOPY(descript, olddescript);
1253 			TDSETPOS(descript, grabpoint);
1254 		} else
1255 		{
1256 			/* get co-ordinates of cursor */
1257 			if (us_demandxy(&xcur, &ycur))
1258 			{
1259 				us_pophighlight(FALSE);
1260 				return;
1261 			}
1262 			gridalign(&xcur, &ycur, 1, np);
1263 
1264 			/* adjust the cursor position if selecting interactively */
1265 			if ((us_tool->toolstate&INTERACTIVE) != 0)
1266 			{
1267 				us_textgrabinit(olddescript, xw, yw, adjxc, adjyc, high->fromgeom);
1268 				trackcursor(FALSE, us_ignoreup, us_textgrabbegin, us_textgrabdown,
1269 					us_stopandpoponchar, us_dragup, TRACKDRAGGING);
1270 				if (el_pleasestop != 0) return;
1271 				if (us_demandxy(&xcur, &ycur)) return;
1272 			}
1273 
1274 			/* determine grab point from current cursor location */
1275 			TDCOPY(descript, olddescript);
1276 			us_figuregrabpoint(descript, xcur, ycur, adjxc, adjyc, xw, yw);
1277 		}
1278 
1279 		/* set the new descriptor */
1280 		startobjectchange((INTBIG)high->fromgeom->entryaddr.blind,
1281 			high->fromgeom->entryisnode ? VNODEINST : VARCINST);
1282 		us_rotatedescriptI(high->fromgeom, descript);
1283 		us_modifytextdescript(high, descript);
1284 
1285 		/* redisplay the text */
1286 		endobjectchange((INTBIG)high->fromgeom->entryaddr.blind,
1287 			high->fromgeom->entryisnode ? VNODEINST : VARCINST);
1288 
1289 		/* restore highlighting */
1290 		us_pophighlight(FALSE);
1291 		return;
1292 	}
1293 
1294 	if (namesamen(pp, x_("size"), l) == 0 && l >= 2)
1295 	{
1296 		if (count < 2)
1297 		{
1298 			ttyputusage(x_("text size SCALE"));
1299 			return;
1300 		}
1301 
1302 		/* get old descriptor */
1303 		if (high->fromvar != NOVARIABLE)
1304 		{
1305 			TDCOPY(olddescript, high->fromvar->textdescript);
1306 		} else if (high->fromport != NOPORTPROTO)
1307 		{
1308 			TDCOPY(olddescript, high->fromport->textdescript);
1309 		} else if (high->fromgeom->entryisnode)
1310 		{
1311 			ni = high->fromgeom->entryaddr.ni;
1312 			TDCOPY(olddescript, ni->textdescript);
1313 		}
1314 		font = TDGETSIZE(olddescript);
1315 		font = us_gettextsize(par[1], font);
1316 		if (font < 0) return;
1317 
1318 		/* save highlighting */
1319 		us_pushhighlight();
1320 		us_clearhighlightcount();
1321 
1322 		/* set the new size */
1323 		startobjectchange((INTBIG)high->fromgeom->entryaddr.blind,
1324 			high->fromgeom->entryisnode ? VNODEINST : VARCINST);
1325 
1326 		TDSETSIZE(olddescript, font);
1327 		us_modifytextdescript(high, olddescript);
1328 
1329 		/* redisplay the text */
1330 		endobjectchange((INTBIG)high->fromgeom->entryaddr.blind,
1331 			high->fromgeom->entryisnode ? VNODEINST : VARCINST);
1332 
1333 		/* restore highlighting */
1334 		us_pophighlight(FALSE);
1335 		return;
1336 	}
1337 
1338 	if (namesamen(pp, x_("interior-only"), l) == 0)
1339 	{
1340 		if (high->fromvar == NOVARIABLE)
1341 		{
1342 			us_abortcommand(_("Interior style only applies to text variables"));
1343 			return;
1344 		}
1345 		if (!high->fromgeom->entryisnode)
1346 		{
1347 			us_abortcommand(_("Interior style only applies to nodes"));
1348 			return;
1349 		}
1350 
1351 		ni = high->fromgeom->entryaddr.ni;
1352 		startobjectchange((INTBIG)ni, VNODEINST);
1353 		TDCOPY(descript, high->fromvar->textdescript);
1354 		TDSETINTERIOR(descript, VTINTERIOR);
1355 		us_modifytextdescript(high, descript);
1356 		endobjectchange((INTBIG)ni, VNODEINST);
1357 		return;
1358 	}
1359 
1360 	if (namesamen(pp, x_("exterior"), l) == 0 && l >= 2)
1361 	{
1362 		if (high->fromvar == NOVARIABLE)
1363 		{
1364 			us_abortcommand(_("Interior style only applies to text variables"));
1365 			return;
1366 		}
1367 		if (!high->fromgeom->entryisnode)
1368 		{
1369 			us_abortcommand(_("Interior style only applies to nodes"));
1370 			return;
1371 		}
1372 		ni = high->fromgeom->entryaddr.ni;
1373 		startobjectchange((INTBIG)ni, VNODEINST);
1374 		TDCOPY(descript, high->fromvar->textdescript);
1375 		TDSETINTERIOR(descript, 0);
1376 		us_modifytextdescript(high, descript);
1377 		endobjectchange((INTBIG)ni, VNODEINST);
1378 		return;
1379 	}
1380 
1381 	ttyputbadusage(x_("text"));
1382 }
1383 
us_undo(INTBIG count,CHAR * par[])1384 void us_undo(INTBIG count, CHAR *par[])
1385 {
1386 	REGISTER INTBIG ret, i, j;
1387 	REGISTER BOOLEAN majorchange, doingundo;
1388 	REGISTER CHAR *direction;
1389 	TOOL *tool;
1390 	REGISTER NODEPROTO *np;
1391 	REGISTER LIBRARY *lib;
1392 	INTBIG *totals;
1393 
1394 	if (count > 0 && namesamen(par[0], x_("clear"), estrlen(par[0])) == 0)
1395 	{
1396 		noundoallowed();
1397 		return;
1398 	}
1399 
1400 	if (count > 0 && namesamen(par[0], x_("save"), estrlen(par[0])) == 0)
1401 	{
1402 		if (count < 2)
1403 		{
1404 			ttyputusage(x_("undo save AMOUNT"));
1405 			return;
1406 		}
1407 
1408 		/* set new history list size */
1409 		i = eatoi(par[1]);
1410 		if (i <= 0)
1411 		{
1412 			us_abortcommand(_("Must have positive history list size"));
1413 			return;
1414 		}
1415 		j = historylistsize(i);
1416 		ttyputverbose(M_("History list size changed from %ld to %ld entries"), j, i);
1417 		return;
1418 	}
1419 
1420 	doingundo = TRUE;
1421 	direction = x_("undo");
1422 	if (count > 0 && namesamen(par[0], x_("redo"), estrlen(par[0])) == 0)
1423 	{
1424 		count--;
1425 		doingundo = FALSE;
1426 		direction = x_("redo");
1427 	}
1428 
1429 	/* special case if current window is text editor: undo handled by editor */
1430 	if (el_curwindowpart != NOWINDOWPART && doingundo)
1431 	{
1432 		if ((el_curwindowpart->state&WINDOWTYPE) == POPTEXTWINDOW ||
1433 			(el_curwindowpart->state&WINDOWTYPE) == TEXTWINDOW)
1434 		{
1435 			us_undotext(el_curwindowpart);
1436 			return;
1437 		}
1438 	}
1439 
1440 	if (count != 0)
1441 	{
1442 		i = eatoi(par[0]);
1443 		if (i <= 0)
1444 		{
1445 			us_abortcommand(_("Must %s a positive number of changes"), direction);
1446 			return;
1447 		}
1448 	} else i = -1;
1449 
1450 	/* do the undo */
1451 	totals = (INTBIG *)emalloc((el_maxtools * SIZEOFINTBIG), el_tempcluster);
1452 	if (totals == 0)
1453 	{
1454 		ttyputnomemory();
1455 		return;
1456 	}
1457 	for(j=0; j<el_maxtools; j++) totals[j] = 0;
1458 
1459 	/* do the undo/redo */
1460 	majorchange = FALSE;
1461 	for(j=0; ; j++)
1462 	{
1463 		if (doingundo) ret = undoabatch(&tool); else
1464 			ret = redoabatch(&tool);
1465 		if (ret == 0)
1466 		{
1467 			if (j != 0) ttyputmsg(_("Partial change %sne"), direction); else
1468 				us_abortcommand(_("No changes to %s"), direction);
1469 			break;
1470 		}
1471 		totals[tool->toolindex]++;
1472 		if (i < 0)
1473 		{
1474 			/* no batch count specified: go back to significant change */
1475 			if (ret > 0) majorchange = TRUE;
1476 			if (majorchange)
1477 			{
1478 				/* if redoing, keep on redoing unimportant batches */
1479 				if (!doingundo)
1480 				{
1481 					for(;;)
1482 					{
1483 						if (undonature(FALSE) >= 0) break;
1484 						(void)redoabatch(&tool);
1485 					}
1486 				}
1487 				break;
1488 			}
1489 		} else
1490 		{
1491 			/* batch count given: stop when requested number done */
1492 			if (j >= i-1) break;
1493 		}
1494 	}
1495 
1496 	for(j=0; j<el_maxtools; j++) if (totals[j] != 0)
1497 		ttyputverbose(x_("%ld %s %s %sne"), totals[j], el_tools[j].toolname,
1498 			makeplural(_("change"), totals[j]), direction);
1499 	efree((CHAR *)totals);
1500 
1501 	/* if a cell is the current node, make sure it still exists */
1502 	if (us_curnodeproto != NONODEPROTO && us_curnodeproto->primindex == 0 &&
1503 		(us_state&NONPERSISTENTCURNODE) == 0)
1504 	{
1505 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1506 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1507 				if (us_curnodeproto == np) break;
1508 		if (np == NONODEPROTO)
1509 		{
1510 			np = el_curlib->firstnodeproto;
1511 			if (np == NONODEPROTO) np = el_curtech->firstnodeproto;
1512 			us_setnodeproto(np);
1513 		}
1514 	}
1515 }
1516 
1517 /*
1518  * routine to determine whether the string "testcase" satisfies the pattern "pattern".
1519  * Returns true if it matches.
1520  */
1521 static BOOLEAN us_patternmatch(CHAR *pattern, CHAR *testcase);
1522 static BOOLEAN us_patternmatchhere(CHAR *pattern, CHAR *testcase);
1523 
us_patternmatch(CHAR * pattern,CHAR * testcase)1524 BOOLEAN us_patternmatch(CHAR *pattern, CHAR *testcase)
1525 {
1526 	REGISTER INTBIG i, testlen;
1527 
1528 	/* loop through every position in the testcase, seeing if the pattern matches */
1529 	testlen = estrlen(testcase);
1530 	for(i=0; i<testlen; i++)
1531 		if (us_patternmatchhere(pattern, &testcase[i]) != 0) return(TRUE);
1532 
1533 	/* not a match */
1534 	return(FALSE);
1535 }
1536 
us_patternmatchhere(CHAR * pattern,CHAR * testcase)1537 BOOLEAN us_patternmatchhere(CHAR *pattern, CHAR *testcase)
1538 {
1539 	REGISTER INTBIG i, j, patlen;
1540 	CHAR *subpattern;
1541 
1542 	/* loop through every character in the pattern, seeing if it matches */
1543 	patlen = estrlen(pattern);
1544 	for(i=0; i<patlen; i++)
1545 	{
1546 		if (pattern[i] == '*')
1547 		{
1548 			subpattern = &pattern[i+1];
1549 			if (*subpattern == 0) return(TRUE);
1550 			for(j=0; testcase[i+j] != 0; j++)
1551 			{
1552 				if (us_patternmatchhere(subpattern, &testcase[i+j])) return(TRUE);
1553 			}
1554 			return(FALSE);
1555 		}
1556 		if (pattern[i] != testcase[i]) return(FALSE);
1557 	}
1558 
1559 	/* made it through the pattern, it matches */
1560 	return(TRUE);
1561 }
1562 
us_var(INTBIG count,CHAR * par[])1563 void us_var(INTBIG count, CHAR *par[])
1564 {
1565 	REGISTER BOOLEAN negated, inplace;
1566 	REGISTER INTBIG maxleng, i, j, k, l, function, newval, search, oldaddr, language,
1567 		annotate, *newarray, oldlen, len1, len2, count1, count2, count3, disppart;
1568 	INTBIG aindex, objaddr, objaddr1, objaddr2, objtype, objtype1, objtype2, newtype, newaddr;
1569 	UINTBIG newdescript[TEXTDESCRIPTSIZE];
1570 	INTBIG dummy;
1571 	BOOLEAN comvar;
1572 	BOOLEAN but;
1573 	REGISTER VARIABLE *var, *tvar, *res, *var1, *var2, *nvar;
1574 	static VARIABLE fvar;
1575 	REGISTER GEOM **list, *geom;
1576 	REGISTER NODEINST *ni;
1577 	VARIABLE *evar, fvar1, fvar2;
1578 	REGISTER NODEPROTO *np;
1579 	REGISTER LIBRARY *lib;
1580 	REGISTER ARCPROTO *ap;
1581 	POPUPMENU *me, *cme;
1582 	REGISTER POPUPMENUITEM *mi;
1583 	REGISTER WINDOWPART *w, *oldw;
1584 	REGISTER EDITOR *ed;
1585 	REGISTER float oldfloat, oldden, newfloat;
1586 	CHAR *pp, *qual, *qual1, *qual2, varname[100], line[50], *name, *code,
1587 		*dummyfile[1], *header, *edname, *savequal, qualname[300];
1588 	extern COMCOMP us_varvep, us_varvdp, us_varvsp, us_varvalp, us_varvalcp;
1589 	static CHAR nullstr[] = {x_("")};
1590 	REGISTER void *infstr;
1591 
1592 	/* show all command interpreter variables if nothing specified */
1593 	if (count == 0)
1594 	{
1595 		j = 0;
1596 		for(i=0; i<52; i++)
1597 		{
1598 			if (i < 26) l = 'a' + i; else
1599 				l = 'A' + i - 26;
1600 			var = getval((INTBIG)us_tool, VTOOL, -1, us_commandvarname((INTSML)l));
1601 			if (var == NOVARIABLE) continue;
1602 			(void)esnprintf(varname, 100, x_("%%%c"), (CHAR)l);
1603 			ttyputmsg(_("%s variable '%s' is %s"), us_variableattributes(var, -1),
1604 				varname, describevariable(var, -1, 0));
1605 			j++;
1606 		}
1607 		if (j == 0) ttyputmsg(_("No command interpreter variables are set"));
1608 		return;
1609 	}
1610 
1611 	/* get the variable option */
1612 	l = estrlen(pp = par[0]);
1613 
1614 	if (namesamen(pp, x_("options"), l) == 0 && l >= 2)
1615 	{
1616 		if (count <= 1)
1617 		{
1618 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_ignoreoptionchangeskey);
1619 			if (var == NOVARIABLE)
1620 				ttyputmsg(_("Option changes are being tracked")); else
1621 					ttyputmsg(_("Option changes are being ignored"));
1622 			return;
1623 		}
1624 		l = estrlen(pp = par[1]);
1625 		if (namesamen(pp, x_("ignore"), l) == 0)
1626 		{
1627 			(void)setvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey, 1,
1628 				VINTEGER|VDONTSAVE);
1629 			ttyputverbose(M_("Option changes are being ignored"));
1630 			return;
1631 		}
1632 		if (namesamen(pp, x_("track"), l) == 0)
1633 		{
1634 			var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_ignoreoptionchangeskey);
1635 			if (var != NOVARIABLE)
1636 				(void)delvalkey((INTBIG)us_tool, VTOOL, us_ignoreoptionchangeskey);
1637 			ttyputverbose(M_("Option changes are being tracked"));
1638 			return;
1639 		}
1640 		if (namesamen(pp, x_("save"), l) == 0)
1641 		{
1642 			us_saveoptions();
1643 			return;
1644 		}
1645 		ttyputusage(x_("var options [ignore | track | save]"));
1646 		return;
1647 	}
1648 
1649 	if (namesamen(pp, x_("reinherit"), l) == 0 && l >= 3)
1650 	{
1651 		list = us_gethighlighted(WANTNODEINST, 0, 0);
1652 		if (list[0] == NOGEOM)
1653 		{
1654 			us_abortcommand(_("Must select nodes for reinheriting attributes"));
1655 			return;
1656 		}
1657 		for(i=0; list[i] != NOGEOM; i++)
1658 		{
1659 			geom = list[i];
1660 			if (!geom->entryisnode) continue;
1661 			ni = geom->entryaddr.ni;
1662 			us_inheritattributes(ni);
1663 		}
1664 		ttyputmsg(_("%ld nodes have had their parameters reinherited"), i);
1665 		return;
1666 	}
1667 
1668 	if (namesamen(pp, x_("total-reinherit"), l) == 0 && l >= 9)
1669 	{
1670 		ttyputmsg(_("Reinheriting parameters on all instances in all libraries..."));
1671 		i = 0;
1672 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1673 		{
1674 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1675 			{
1676 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1677 				{
1678 					us_inheritattributes(ni);
1679 					i++;
1680 				}
1681 			}
1682 		}
1683 		ttyputmsg(_("%ld nodes have had their parameters reinherited"), i);
1684 		return;
1685 	}
1686 
1687 
1688 	if (namesamen(pp, x_("relocate"), l) == 0 && l >= 3)
1689 	{
1690 		list = us_gethighlighted(WANTNODEINST, 0, 0);
1691 		if (list[0] == NOGEOM)
1692 		{
1693 			us_abortcommand(_("Must select nodes for relocating attributes"));
1694 			return;
1695 		}
1696 		j = 0;
1697 		for(i=0; list[i] != NOGEOM; i++)
1698 		{
1699 			geom = list[i];
1700 			if (!geom->entryisnode) continue;
1701 			ni = geom->entryaddr.ni;
1702 			if (us_adjustparameterlocations(ni)) j++;
1703 		}
1704 		ttyputmsg(_("%ld nodes have had their parameters relocated"), j);
1705 		return;
1706 	}
1707 
1708 	if (namesamen(pp, x_("total-relocate"), l) == 0 && l >= 9)
1709 	{
1710 		ttyputmsg(_("Relocating parameters on all instances in all libraries..."));
1711 		i = 0;
1712 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1713 		{
1714 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1715 			{
1716 				for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1717 				{
1718 					if (us_adjustparameterlocations(ni)) i++;
1719 				}
1720 			}
1721 		}
1722 		ttyputmsg(_("%ld nodes have had their parameters relocated"), i);
1723 		return;
1724 	}
1725 
1726 	if (namesamen(pp, x_("visible-all"), l) == 0 && l >= 9)
1727 	{
1728 		/* make all parameters on the current node(s) visible */
1729 		list = us_gethighlighted(WANTNODEINST, 0, 0);
1730 		for(i=0; list[i] != NOGEOM; i++)
1731 		{
1732 			ni = list[i]->entryaddr.ni;
1733 			if (ni->proto->primindex != 0) continue;
1734 			for(j=0; j<ni->numvar; j++)
1735 			{
1736 				var = &ni->firstvar[j];
1737 				nvar = us_findparametersource(var, ni);
1738 				if (nvar == NOVARIABLE) continue;
1739 				if ((var->type&VDISPLAY) != 0) continue;
1740 				startobjectchange((INTBIG)ni, VNODEINST);
1741 				var->type |= VDISPLAY;
1742 				endobjectchange((INTBIG)ni, VNODEINST);
1743 			}
1744 		}
1745 		return;
1746 	}
1747 
1748 	if (namesamen(pp, x_("visible-none"), l) == 0 && l >= 9)
1749 	{
1750 		/* make all parameters on the current node(s) invisible */
1751 		list = us_gethighlighted(WANTNODEINST, 0, 0);
1752 		for(i=0; list[i] != NOGEOM; i++)
1753 		{
1754 			ni = list[i]->entryaddr.ni;
1755 			if (ni->proto->primindex != 0) continue;
1756 			for(j=0; j<ni->numvar; j++)
1757 			{
1758 				var = &ni->firstvar[j];
1759 				nvar = us_findparametersource(var, ni);
1760 				if (nvar == NOVARIABLE) continue;
1761 				if ((var->type&VDISPLAY) == 0) continue;
1762 				startobjectchange((INTBIG)ni, VNODEINST);
1763 				var->type &= ~VDISPLAY;
1764 				endobjectchange((INTBIG)ni, VNODEINST);
1765 			}
1766 		}
1767 		return;
1768 	}
1769 
1770 	if (namesamen(pp, x_("visible-default"), l) == 0 && l >= 9)
1771 	{
1772 		/* make all parameters on the current node(s) visible or invisible according to the cell */
1773 		list = us_gethighlighted(WANTNODEINST, 0, 0);
1774 		for(i=0; list[i] != NOGEOM; i++)
1775 		{
1776 			ni = list[i]->entryaddr.ni;
1777 			if (ni->proto->primindex != 0) continue;
1778 			for(j=0; j<ni->numvar; j++)
1779 			{
1780 				var = &ni->firstvar[j];
1781 				nvar = us_findparametersource(var, ni);
1782 				if (nvar == NOVARIABLE) continue;
1783 				if (TDGETINTERIOR(nvar->textdescript) == 0)
1784 				{
1785 					/* prototype wants parameter to be visible */
1786 					if ((var->type&VDISPLAY) != 0) continue;
1787 					startobjectchange((INTBIG)ni, VNODEINST);
1788 					var->type |= VDISPLAY;
1789 					endobjectchange((INTBIG)ni, VNODEINST);
1790 				} else
1791 				{
1792 					/* prototype wants parameter to be invisible */
1793 					if ((var->type&VDISPLAY) == 0) continue;
1794 					startobjectchange((INTBIG)ni, VNODEINST);
1795 					var->type &= ~VDISPLAY;
1796 					endobjectchange((INTBIG)ni, VNODEINST);
1797 				}
1798 			}
1799 		}
1800 		return;
1801 	}
1802 
1803 	if (namesamen(pp, x_("examine"), l) == 0 && l >= 1)
1804 	{
1805 		if (count <= 1)
1806 		{
1807 			count = ttygetparam(M_("Variable: "), &us_varvep, MAXPARS-1, &par[1]) + 1;
1808 			if (count == 1)
1809 			{
1810 				us_abortedmsg();
1811 				return;
1812 			}
1813 		}
1814 		if (us_getvar(par[1], &objaddr, &objtype, &qual, &comvar, &aindex))
1815 		{
1816 			us_abortcommand(_("Incorrect variable name: %s"), par[1]);
1817 			return;
1818 		}
1819 		code = 0;
1820 		if (*qual != 0)
1821 		{
1822 			search = initobjlist(objaddr, objtype, FALSE);
1823 			if (search == 0)
1824 			{
1825 				us_abortcommand(_("Object is invalid"));
1826 				return;
1827 			}
1828 			for(;;)
1829 			{
1830 				pp = nextobjectlist(&evar, search);
1831 				if (pp == 0)
1832 				{
1833 					us_abortcommand(_("No variable %s on the object"), qual);
1834 					return;
1835 				}
1836 				if (namesame(pp, qual) == 0) break;
1837 			}
1838 			language = evar->type & (VCODE1|VCODE2);
1839 			if (language != 0)
1840 			{
1841 				code = (CHAR *)evar->addr;
1842 				fvar.key = evar->key;
1843 				fvar.type = evar->type;
1844 				var = doquerry(code, language, evar->type);
1845 				if (var == NOVARIABLE) code = 0; else
1846 				{
1847 					var->key = evar->key;
1848 					TDCOPY(var->textdescript, evar->textdescript);
1849 					evar = var;
1850 				}
1851 			}
1852 			var = evar;
1853 		} else
1854 		{
1855 			fvar.addr = objaddr;   fvar.type = objtype;
1856 			var = &fvar;
1857 		}
1858 		if (aindex >= 0 && (var->type&VISARRAY) == 0)
1859 		{
1860 			us_abortcommand(_("%s is not an indexable array"), par[1]);
1861 			return;
1862 		}
1863 		(void)esnprintf(varname, 100, x_("%c%s"), (comvar ? '%' : '$'), par[1]);
1864 		infstr = initinfstr();
1865 		if (code != 0)
1866 		{
1867 			addstringtoinfstr(infstr, code);
1868 			addstringtoinfstr(infstr, x_(" => "));
1869 		}
1870 		addstringtoinfstr(infstr, describevariable(var, aindex, 0));
1871 		ttyputmsg(_("%s variable '%s' is %s"), us_variableattributes(var, aindex),
1872 			varname, returninfstr(infstr));
1873 		return;
1874 	}
1875 
1876 	if (namesamen(pp, x_("change"), l) == 0 && l >= 1)
1877 	{
1878 		if (count <= 2)
1879 		{
1880 			ttyputusage(x_("var change VARIABLE STYLE"));
1881 			return;
1882 		}
1883 		if (us_getvar(par[1], &objaddr, &objtype, &qual, &comvar, &aindex))
1884 		{
1885 			us_abortcommand(_("Incorrect variable name: %s"), par[1]);
1886 			return;
1887 		}
1888 		if (comvar)
1889 		{
1890 			us_abortcommand(_("Can only modify database ($) variables"));
1891 			return;
1892 		}
1893 		if (*qual != 0)
1894 		{
1895 			var = getval(objaddr, objtype, -1, qual);
1896 			if (var == NOVARIABLE)
1897 			{
1898 				us_abortcommand(_("No variable %s on the object"), qual);
1899 				return;
1900 			}
1901 		} else
1902 		{
1903 			fvar.addr = objaddr;   fvar.type = objtype;
1904 			var = &fvar;
1905 		}
1906 		if (aindex >= 0 && (var->type&VISARRAY) == 0)
1907 		{
1908 			us_abortcommand(_("%s is not an indexable array"), par[1]);
1909 			return;
1910 		}
1911 
1912 		/* make the change */
1913 		l = estrlen(pp = par[2]);
1914 		negated = FALSE;
1915 		if (namesamen(pp, x_("not"), l) == 0 && l >= 2)
1916 		{
1917 			negated = TRUE;
1918 			par++;
1919 			count--;
1920 			if (count <= 2)
1921 			{
1922 				ttyputusage(x_("var change VARIABLE not STYLE"));
1923 				return;
1924 			}
1925 			l = estrlen(pp = par[2]);
1926 		}
1927 		if ((namesamen(pp, x_("display"), l) == 0 && l >= 1) ||
1928 			(namesamen(pp, x_("na-va-display"), l) == 0 && l >= 2) ||
1929 			(namesamen(pp, x_("in-na-va-display"), l) == 0 && l >= 3) ||
1930 			(namesamen(pp, x_("inall-na-va-display"), l) == 0 && l >= 3))
1931 		{
1932 			/* compute the new type field */
1933 			TDCOPY(newdescript, var->textdescript);
1934 			us_figurevariableplace(newdescript, count-3, &par[3]);
1935 
1936 			/* signal start of change to nodes and arcs */
1937 			if (objtype == VNODEINST || objtype == VARCINST)
1938 			{
1939 				us_pushhighlight();
1940 				us_clearhighlightcount();
1941 				startobjectchange(objaddr, objtype);
1942 			} else if (objtype == VNODEPROTO)
1943 			{
1944 				us_undrawcellvariable(var, (NODEPROTO *)objaddr);
1945 			}
1946 
1947 			/* change the variable */
1948 			if (!negated)
1949 			{
1950 				var->type |= VDISPLAY;
1951 				modifydescript(objaddr, objtype, var, newdescript);
1952 			} else var->type &= ~VDISPLAY;
1953 			disppart = 0;
1954 			if (namesamen(pp, x_("display"), l) == 0 && l >= 1)
1955 				disppart = VTDISPLAYVALUE; else
1956 			if (namesamen(pp, x_("na-va-display"), l) == 0 && l >= 2)
1957 				disppart = VTDISPLAYNAMEVALUE; else
1958 			if (namesamen(pp, x_("in-na-va-display"), l) == 0 && l >= 3)
1959 				disppart = VTDISPLAYNAMEVALINH; else
1960 			if (namesamen(pp, x_("inall-na-va-display"), l) == 0 && l >= 3)
1961 				disppart = VTDISPLAYNAMEVALINHALL;
1962 			if ((disppart == VTDISPLAYNAMEVALINH || disppart == VTDISPLAYNAMEVALINHALL) &&
1963 			    (objtype&VTYPE) != VNODEPROTO)
1964 			{
1965 				ttyputmsg(_("%s is allowed for cells only, changing to na-va-display"), pp);
1966 				disppart = VTDISPLAYNAMEVALUE;
1967 			}
1968 			TDSETDISPPART(var->textdescript, disppart);
1969 
1970 			/* signal end of change to nodes and arcs */
1971 			if (objtype == VNODEINST || objtype == VARCINST)
1972 			{
1973 				endobjectchange(objaddr, objtype);
1974 				us_pophighlight(FALSE);
1975 			} else if (objtype == VNODEPROTO)
1976 			{
1977 				us_drawcellvariable(var, (NODEPROTO *)objaddr);
1978 			}
1979 			return;
1980 		}
1981 		if (negated && namesamen(pp, x_("language"), l) == 0 && l >= 1)
1982 		{
1983 			var->type |= (VCODE1|VCODE2);
1984 			return;
1985 		}
1986 		if (!negated && namesamen(pp, x_("lisp"), l) == 0 && l >= 1)
1987 		{
1988 			var->type |= VLISP;
1989 			return;
1990 		}
1991 		if (!negated && namesamen(pp, x_("tcl"), l) == 0 && l >= 1)
1992 		{
1993 			var->type |= VTCL;
1994 			return;
1995 		}
1996 		if (!negated && namesamen(pp, x_("java"), l) == 0 && l >= 1)
1997 		{
1998 			var->type |= VJAVA;
1999 			return;
2000 		}
2001 		if (namesamen(pp, x_("temporary"), l) == 0 && l >= 1)
2002 		{
2003 			if (!negated) var->type |= VDONTSAVE; else
2004 				var->type &= ~VDONTSAVE;
2005 			return;
2006 		}
2007 		if (namesamen(pp, x_("cannot-change"), l) == 0 && l >= 1)
2008 		{
2009 			if (!negated) var->type |= VCANTSET; else
2010 				var->type &= ~VCANTSET;
2011 			return;
2012 		}
2013 		if (namesamen(pp, x_("interior-only"), l) == 0 && l >= 3)
2014 		{
2015 			if (!negated)
2016 			{
2017 				TDSETINTERIOR(var->textdescript, VTINTERIOR);
2018 			} else
2019 			{
2020 				TDSETINTERIOR(var->textdescript, 0);
2021 			}
2022 			return;
2023 		}
2024 		ttyputbadusage(x_("var change"));
2025 		return;
2026 	}
2027 
2028 	if (namesamen(pp, x_("delete"), l) == 0 && l >= 1)
2029 	{
2030 		if (count <= 1)
2031 		{
2032 			count = ttygetparam(_("Variable: "), &us_varvdp, MAXPARS-1, &par[1]) + 1;
2033 			if (count == 1)
2034 			{
2035 				us_abortedmsg();
2036 				return;
2037 			}
2038 		}
2039 		if (us_getvar(par[1], &objaddr, &objtype, &qual, &comvar, &aindex))
2040 		{
2041 			us_abortcommand(_("Incorrect variable name: %s"), par[1]);
2042 			return;
2043 		}
2044 		if (comvar)
2045 		{
2046 			us_abortcommand(_("Can't delete command interpreter variables yet"));
2047 			return;
2048 		}
2049 		if (aindex >= 0)
2050 		{
2051 			us_abortcommand(_("Cannot delete a single variable entry"));
2052 			return;
2053 		}
2054 		if (*qual == 0)
2055 		{
2056 			us_abortcommand(_("Must delete a variable ON some object"));
2057 			return;
2058 		}
2059 		(void)allocstring(&savequal, qual, el_tempcluster);
2060 		var = getval(objaddr, objtype, -1, savequal);
2061 		if (var == NOVARIABLE)
2062 		{
2063 			efree(savequal);
2064 			us_abortcommand(_("No variable %s to delete"), savequal);
2065 			return;
2066 		}
2067 
2068 		/* signal start of change to nodes and arcs */
2069 		if (objtype == VNODEINST || objtype == VARCINST)
2070 		{
2071 			us_pushhighlight();
2072 			us_clearhighlightcount();
2073 			startobjectchange(objaddr, objtype);
2074 		} else if (objtype == VNODEPROTO)
2075 		{
2076 			us_undrawcellvariable(var, (NODEPROTO *)objaddr);
2077 		}
2078 
2079 		if (delval(objaddr, objtype, savequal))
2080 			ttyputerr(_("Problem deleting variable %s"), par[1]);
2081 
2082 		/* signal end of change to nodes and arcs */
2083 		if (objtype == VNODEINST || objtype == VARCINST)
2084 		{
2085 			endobjectchange(objaddr, objtype);
2086 			us_pophighlight(FALSE);
2087 		}
2088 		efree(savequal);
2089 		return;
2090 	}
2091 
2092 	if (namesamen(pp, x_("textedit"), l) == 0 && l >= 2)
2093 	{
2094 		if (count <= 1)
2095 		{
2096 			count = ttygetparam(M_("Variable: "), &us_varvep, MAXPARS-1, &par[1]) + 1;
2097 			if (count == 1)
2098 			{
2099 				us_abortedmsg();
2100 				return;
2101 			}
2102 		}
2103 		header = 0;
2104 		inplace = FALSE;
2105 		name = par[1];
2106 		while (count > 2)
2107 		{
2108 			l = estrlen(pp=par[2]);
2109 			if (namesamen(pp, x_("header"), l) == 0)
2110 			{
2111 				if (count > 3) header = par[3]; else
2112 				{
2113 					ttyputusage(x_("var textedit VARIABLE header HEADER"));
2114 					return;
2115 				}
2116 				count--;
2117 				par++;
2118 			} else if (namesamen(pp, x_("in-place"), l) == 0)
2119 			{
2120 				inplace = TRUE;
2121 			} else
2122 			{
2123 				ttyputbadusage(x_("var textedit"));
2124 				return;
2125 			}
2126 			count--;
2127 			par++;
2128 		}
2129 		if (us_getvar(name, &objaddr, &objtype, &qual, &comvar, &aindex))
2130 		{
2131 			us_abortcommand(_("Incorrect variable name: %s"), name);
2132 			return;
2133 		}
2134 		if (*qual != 0)
2135 		{
2136 			var = getval(objaddr, objtype, -1, qual);
2137 			if (var == NOVARIABLE)
2138 			{
2139 				dummyfile[0] = x_("");
2140 				(void)setval(objaddr, objtype, qual, (INTBIG)dummyfile, VSTRING|VISARRAY|(1<<VLENGTHSH));
2141 				var = getval(objaddr, objtype, -1, qual);
2142 				if (var == NOVARIABLE)
2143 				{
2144 					us_abortcommand(_("Cannot create %s on the object"), qual);
2145 					return;
2146 				}
2147 				ttyputverbose(M_("Creating %s on the object"), qual);
2148 			}
2149 			fvar.addr = var->addr;   fvar.type = var->type;
2150 			fvar.key = var->key;     TDCOPY(fvar.textdescript, var->textdescript);
2151 		} else
2152 		{
2153 			fvar.addr = objaddr;   fvar.type = objtype;
2154 		}
2155 		var = &fvar;
2156 
2157 		if (inplace)
2158 		{
2159 			if ((var->type&VDISPLAY) == 0)
2160 			{
2161 				us_abortcommand(_("Only displayable variables can be edited in place"));
2162 				return;
2163 			}
2164 			if ((var->type&VTYPE) != VSTRING)
2165 			{
2166 				us_abortcommand(_("Only string variables can be edited in place"));
2167 				return;
2168 			}
2169 
2170 			/* save and clear highlighting */
2171 			us_pushhighlight();
2172 			us_clearhighlightcount();
2173 
2174 			/* edit the variable */
2175 			us_editvariabletext(var, objtype, objaddr, qual);
2176 
2177 			/* restore highlighting */
2178 			us_pophighlight(FALSE);
2179 			return;
2180 		}
2181 
2182 		if ((var->type&VISARRAY) == 0)
2183 		{
2184 			/* ensure that the variable is settable */
2185 			if ((var->type&VCANTSET) != 0)
2186 			{
2187 				ttyputmsg(_("Variable cannot be changed; use 'examine' option"));
2188 				return;
2189 			}
2190 
2191 			/* save the information about this variable */
2192 			if (us_varqualsave == 0) (void)allocstring(&us_varqualsave, qual, us_tool->cluster); else
2193 				(void)reallocstring(&us_varqualsave, qual, us_tool->cluster);
2194 
2195 			/* create the editor window and load it with the variable */
2196 			if (header == 0)
2197 			{
2198 				infstr = initinfstr();
2199 				us_describeeditor(&edname);
2200 				addstringtoinfstr(infstr, edname);
2201 				addstringtoinfstr(infstr, _(" Editor for variable: "));
2202 				addstringtoinfstr(infstr, name);
2203 				header = returninfstr(infstr);
2204 			}
2205 			us_wpop = us_makeeditor(NOWINDOWPART, header, &dummy, &dummy);
2206 			if (us_wpop == NOWINDOWPART) return;
2207 
2208 			ed = us_wpop->editor;
2209 			ed->editobjqual = us_varqualsave;
2210 			ed->editobjaddr = (CHAR *)objaddr;
2211 			ed->editobjtype = objtype&VTYPE;
2212 			ed->editobjvar = var;
2213 
2214 			/* turn off editor display as data is loaded into it */
2215 			us_suspendgraphics(us_wpop);
2216 			us_addline(us_wpop, 0, describevariable(var, -1, -1));
2217 			us_resumegraphics(us_wpop);
2218 
2219 			/* loop on input */
2220 			oldw = el_curwindowpart;
2221 			el_curwindowpart = us_wpop;
2222 			ttyputverbose(M_("You are typing to the editor"));
2223 			modalloop(us_wpopcharhandler, us_wpopbuttonhandler, us_normalcursor);
2224 			el_curwindowpart = oldw;
2225 
2226 			/* read back the contents of the editor window */
2227 			(void)allocstring(&pp, us_getline(us_wpop, 0), el_tempcluster);
2228 
2229 			/* terminate this popup window */
2230 			startobjectchange((INTBIG)us_tool, VTOOL);
2231 			killwindowpart(us_wpop);
2232 			endobjectchange((INTBIG)us_tool, VTOOL);
2233 
2234 			/* signal start of change to nodes and arcs */
2235 			if ((objtype&VTYPE) == VNODEINST || (objtype&VTYPE) == VARCINST)
2236 			{
2237 				us_pushhighlight();
2238 				us_clearhighlightcount();
2239 				startobjectchange(objaddr, objtype&VTYPE);
2240 			}
2241 
2242 			switch (ed->editobjvar->type&VTYPE)
2243 			{
2244 				case VINTEGER:
2245 				case VSHORT:
2246 				case VADDRESS:
2247 					res = setval((INTBIG)ed->editobjaddr, ed->editobjtype,
2248 						ed->editobjqual, myatoi(pp), ed->editobjvar->type);
2249 					break;
2250 				case VFLOAT:
2251 				case VDOUBLE:
2252 					newfloat = (float)eatof(pp);
2253 					res = setval((INTBIG)ed->editobjaddr, ed->editobjtype,
2254 						ed->editobjqual, castint(newfloat), ed->editobjvar->type);
2255 					break;
2256 				case VSTRING:
2257 					res = setval((INTBIG)ed->editobjaddr, ed->editobjtype,
2258 						ed->editobjqual, (INTBIG)pp, ed->editobjvar->type);
2259 					break;
2260 				case VPORTPROTO:
2261 					us_renameport((PORTPROTO *)ed->editobjaddr, pp);
2262 					break;
2263 				default:
2264 					ttyputmsg(_("Cannot update this type of variable"));
2265 					break;
2266 			}
2267 			if (res == NOVARIABLE) ttyputerr(_("Error changing variable"));
2268 
2269 			/* signal end of change to nodes and arcs */
2270 			if ((objtype&VTYPE) == VNODEINST || (objtype&VTYPE) == VARCINST)
2271 			{
2272 				endobjectchange(objaddr, objtype&VTYPE);
2273 				us_pophighlight(FALSE);
2274 			}
2275 			efree(pp);
2276 			return;
2277 		}
2278 
2279 		/* array variable: use full editor */
2280 		if (aindex >= 0) ttyputmsg(_("WARNING: index specification being ignored"));
2281 
2282 		/* save the information about this variable */
2283 		if (us_varqualsave == 0) (void)allocstring(&us_varqualsave, qual, us_tool->cluster); else
2284 			(void)reallocstring(&us_varqualsave, qual, us_tool->cluster);
2285 
2286 		/* get a new window, put an editor in it */
2287 		w = us_wantnewwindow(0);
2288 		if (w == NOWINDOWPART) return;
2289 		if (header == 0)
2290 		{
2291 			infstr = initinfstr();
2292 			us_describeeditor(&edname);
2293 			addstringtoinfstr(infstr, edname);
2294 			addstringtoinfstr(infstr, _(" Editor for variable: "));
2295 			addstringtoinfstr(infstr, name);
2296 			header = returninfstr(infstr);
2297 		}
2298 		if (us_makeeditor(w, header, &dummy, &dummy) == NOWINDOWPART) return;
2299 		ed = w->editor;
2300 		ed->editobjqual = us_varqualsave;
2301 		ed->editobjaddr = (CHAR *)objaddr;
2302 		ed->editobjtype = objtype;
2303 		ed->editobjvar = var;
2304 		us_suspendgraphics(w);
2305 
2306 		/* determine the type of this variable for annotation */
2307 		annotate = 0;
2308 		if (us_varqualsave[0] != 0 && (objtype&VTYPE) == VTECHNOLOGY)
2309 		{
2310 			/* these variables correspond to layer names */
2311 			if (namesame(us_varqualsave, x_("SIM_spice_resistance")) == 0 ||
2312 				namesame(us_varqualsave, x_("SIM_spice_capacitance")) == 0 ||
2313 				namesame(us_varqualsave, x_("TECH_layer_function")) == 0 ||
2314 				namesame(us_varqualsave, x_("USER_layer_letters")) == 0 ||
2315 				namesame(us_varqualsave, x_("DRC_max_distances")) == 0 ||
2316 				namesame(us_varqualsave, x_("IO_gds_layer_numbers")) == 0 ||
2317 				namesame(us_varqualsave, x_("IO_dxf_layer_names")) == 0 ||
2318 				namesame(us_varqualsave, x_("IO_cif_layer_names")) == 0 ||
2319 				namesame(us_varqualsave, x_("IO_skill_layer_names")) == 0)
2320 			{
2321 				annotate = 1;
2322 				tvar = getval(objaddr, objtype, VSTRING|VISARRAY, x_("TECH_layer_names"));
2323 				if (tvar == NOVARIABLE) annotate = 0;
2324 			}
2325 
2326 			/* these variables correspond to a primitive nodeproto */
2327 			if (namesame(us_varqualsave, x_("TECH_node_width_offset")) == 0)
2328 			{
2329 				annotate = 2;
2330 				np = ((TECHNOLOGY *)objaddr)->firstnodeproto;
2331 			}
2332 
2333 			/* these variables correspond to a color map */
2334 			if (namesame(us_varqualsave, x_("USER_color_map")) == 0) annotate = 3;
2335 
2336 			/* these variables correspond to an upper-diagonal layer table */
2337 			if (namesame(us_varqualsave, x_("DRC_min_connected_distances")) == 0 ||
2338 				namesame(us_varqualsave, x_("DRC_min_connected_distances_rule")) == 0 ||
2339 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances")) == 0 ||
2340 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances_rule")) == 0 ||
2341 				namesame(us_varqualsave, x_("DRC_min_connected_distances_wide")) == 0 ||
2342 				namesame(us_varqualsave, x_("DRC_min_connected_distances_wide_rule")) == 0 ||
2343 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances_wide")) == 0 ||
2344 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances_wide_rule")) == 0 ||
2345 				namesame(us_varqualsave, x_("DRC_min_connected_distances_multi")) == 0 ||
2346 				namesame(us_varqualsave, x_("DRC_min_connected_distances_multi_rule")) == 0 ||
2347 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances_multi")) == 0 ||
2348 				namesame(us_varqualsave, x_("DRC_min_unconnected_distances_multi_rule")) == 0 ||
2349 				namesame(us_varqualsave, x_("DRC_min_edge_distances")) == 0 ||
2350 				namesame(us_varqualsave, x_("DRC_min_edge_distances_rule")) == 0)
2351 			{
2352 				annotate = 4;
2353 				maxleng = ((TECHNOLOGY *)objaddr)->layercount;
2354 				j = k = 0;
2355 				tvar = getval(objaddr, objtype, VSTRING|VISARRAY, x_("TECH_layer_names"));
2356 				if (tvar == NOVARIABLE) annotate = 0;
2357 			}
2358 
2359 			/* these variables correspond to pairs of X and Y coordinates */
2360 			if (namesame(us_varqualsave, x_("prototype_center")) == 0 ||
2361 				namesame(us_varqualsave, x_("trace")) == 0) annotate = 5;
2362 
2363 			/* these variables correspond to a primitive arcproto */
2364 			if (namesame(us_varqualsave, x_("TECH_arc_width_offset")) == 0)
2365 			{
2366 				annotate = 6;
2367 				ap = ((TECHNOLOGY *)objaddr)->firstarcproto;
2368 			}
2369 		}
2370 
2371 		l = getlength(var);
2372 		for(i=0; i<l; i++)
2373 		{
2374 			infstr = initinfstr();
2375 			addstringtoinfstr(infstr, describevariable(var, i, -1));
2376 			switch (annotate)
2377 			{
2378 				case 0: break;
2379 				case 1:
2380 					if (i < getlength(tvar))
2381 					{
2382 						addstringtoinfstr(infstr, x_("     /* "));
2383 						addstringtoinfstr(infstr, ((CHAR **)tvar->addr)[i]);
2384 						addstringtoinfstr(infstr, x_(" */"));
2385 					}
2386 					break;
2387 				case 2:
2388 					if ((i%4) != 0) break;
2389 					if (np != NONODEPROTO)
2390 					{
2391 						addstringtoinfstr(infstr, x_("     /* "));
2392 						addstringtoinfstr(infstr, np->protoname);
2393 						np = np->nextnodeproto;
2394 						addstringtoinfstr(infstr, x_(" */"));
2395 					}
2396 					break;
2397 				case 3:
2398 					(void)esnprintf(line, 50, M_("     /* entry %ld "), i/4);
2399 					addstringtoinfstr(infstr, line);
2400 					switch (i%4)
2401 					{
2402 						case 0: addstringtoinfstr(infstr, M_("red */"));     break;
2403 						case 1: addstringtoinfstr(infstr, M_("green */"));   break;
2404 						case 2: addstringtoinfstr(infstr, M_("blue */"));    break;
2405 						case 3: addstringtoinfstr(infstr, M_("letter */"));  break;
2406 					}
2407 					break;
2408 				case 4:
2409 					if (j < getlength(tvar) && k < getlength(tvar))
2410 					{
2411 						addstringtoinfstr(infstr, x_("     /* "));
2412 						addstringtoinfstr(infstr, ((CHAR **)tvar->addr)[j]);
2413 						addstringtoinfstr(infstr, x_(" TO "));
2414 						addstringtoinfstr(infstr, ((CHAR **)tvar->addr)[k]);
2415 						addstringtoinfstr(infstr, x_(" */"));
2416 					}
2417 					k++;
2418 					if (k >= maxleng)
2419 					{
2420 						j++;
2421 						k = j;
2422 					}
2423 					break;
2424 				case 5:
2425 					if ((i%1) == 0) (void)esnprintf(line, 50, x_("     /* X[%ld] */"), i/2); else
2426 						(void)esnprintf(line, 50, x_("     /* Y[%ld] */"), i/2);
2427 					addstringtoinfstr(infstr, line);
2428 					break;
2429 				case 6:
2430 					if (ap != NOARCPROTO)
2431 					{
2432 						addstringtoinfstr(infstr, x_("     /* "));
2433 						addstringtoinfstr(infstr, describearcproto(ap));
2434 						ap = ap->nextarcproto;
2435 						addstringtoinfstr(infstr, x_(" */"));
2436 					}
2437 					break;
2438 			}
2439 			us_addline(w, i, returninfstr(infstr));
2440 		}
2441 		us_resumegraphics(w);
2442 		w->changehandler = us_varchanges;
2443 		if (annotate != 0) ed->state |= LINESFIXED;
2444 		return;
2445 	}
2446 
2447 	if (namesamen(pp, x_("pick"), l) == 0 && l >= 1)
2448 	{
2449 		/* get the name of the object to show in a popup menu */
2450 		if (count <= 1)
2451 		{
2452 			count = ttygetparam(_("Object: "), &us_varvep, MAXPARS-1, &par[1]) + 1;
2453 			if (count == 1)
2454 			{
2455 				us_abortedmsg();
2456 				return;
2457 			}
2458 		}
2459 
2460 		/* parse the name into an object, type, qualification, index, etc. */
2461 		if (us_getvar(par[1], &objaddr, &objtype, &qual, &comvar, &aindex))
2462 		{
2463 			us_abortcommand(_("Incorrect variable name: %s"), par[1]);
2464 			return;
2465 		}
2466 
2467 		/* cannot examine database variables */
2468 		if (comvar)
2469 		{
2470 			us_abortcommand(_("Cannot use database variables"));
2471 			return;
2472 		}
2473 
2474 		/* if the object is qualified, examine the qualification */
2475 		if (*qual != 0)
2476 		{
2477 			var = getval(objaddr, objtype, -1, qual);
2478 			if (var == NOVARIABLE)
2479 			{
2480 				us_abortcommand(_("No variable %s on the object"), qual);
2481 				return;
2482 			}
2483 			objaddr = var->addr;   objtype = var->type;
2484 		}
2485 
2486 		/* cannot examine objects with no structure */
2487 		if ((objtype&VTYPE) < VNODEINST || (objtype&VTYPE) == VFRACT || (objtype&VTYPE) == VSHORT || (objtype&VTYPE) == VBOOLEAN)
2488 		{
2489 			us_abortcommand(_("Cannot examine simple objects"));
2490 			return;
2491 		}
2492 
2493 		/* if the object is indexed, grab that entry */
2494 		if (aindex >= 0)
2495 		{
2496 			if ((objtype&VISARRAY) == 0)
2497 			{
2498 				us_abortcommand(_("Variable is not an array: cannot index it"));
2499 				return;
2500 			}
2501 			objaddr = ((INTBIG *)objaddr)[aindex];
2502 			objtype &= ~VISARRAY;
2503 		}
2504 
2505 		/* cannot examine arrays */
2506 		if ((objtype&VISARRAY) != 0)
2507 		{
2508 			us_abortcommand(_("Must pick single entries of arrays"));
2509 			return;
2510 		}
2511 
2512 		/* look through all attributes on the variable */
2513 		search = initobjlist(objaddr, objtype, TRUE);
2514 		if (search == 0)
2515 		{
2516 			us_abortcommand(_("Cannot access variable components"));
2517 			return;
2518 		}
2519 
2520 		/* count the number of nonarray attributes and get longest value */
2521 		maxleng = 0;
2522 		for(j=0; ;)
2523 		{
2524 			pp = nextobjectlist(&evar, search);
2525 			if (pp == 0) break;
2526 			if ((evar->type&VISARRAY) != 0) continue;
2527 			j++;
2528 			i = estrlen(describevariable(evar, -1, 0));
2529 			if (i > maxleng) maxleng = i;
2530 		}
2531 		maxleng += 5;
2532 
2533 		/* allocate the pop-up menu structure */
2534 		me = (POPUPMENU *)emalloc(sizeof(POPUPMENU), el_tempcluster);
2535 		if (me == 0)
2536 		{
2537 			ttyputnomemory();
2538 			return;
2539 		}
2540 		mi = (POPUPMENUITEM *)emalloc((j * (sizeof (POPUPMENUITEM))), el_tempcluster);
2541 		if (mi == 0)
2542 		{
2543 			ttyputnomemory();
2544 			return;
2545 		}
2546 
2547 		/* load up the menu structure */
2548 		search = initobjlist(objaddr, objtype, TRUE);
2549 		if (search == 0)
2550 		{
2551 			us_abortcommand(_("Strange error accessing component"));
2552 			return;
2553 		}
2554 		l = 0;
2555 		for(i=0; ;)
2556 		{
2557 			pp = nextobjectlist(&evar, search);
2558 			if (pp == 0) break;
2559 			if ((evar->type&VISARRAY) != 0) continue;
2560 			if (evar->key == (UINTBIG)-1 || (evar->type&VCANTSET) != 0)
2561 			{
2562 				(void)allocstring(&mi[i].attribute, pp, el_tempcluster);
2563 				mi[i].maxlen = -1;
2564 				mi[i].valueparse = &us_varvalcp;
2565 			} else
2566 			{
2567 				mi[i].attribute = (CHAR *)emalloc((estrlen(pp)+3) * SIZEOFCHAR, el_tempcluster);
2568 				if (mi[i].attribute == 0)
2569 				{
2570 					ttyputnomemory();
2571 					return;
2572 				}
2573 				(void)estrcpy(mi[i].attribute, x_("* "));
2574 				(void)estrcat(mi[i].attribute, pp);
2575 				mi[i].maxlen = maxleng;
2576 				mi[i].valueparse = &us_varvalp;
2577 				l++;
2578 			}
2579 			mi[i].value = (CHAR *)emalloc((maxleng+1) * SIZEOFCHAR, el_tempcluster);
2580 			if (mi[i].value == 0)
2581 			{
2582 				ttyputnomemory();
2583 				return;
2584 			}
2585 			(void)estrcpy(mi[i].value, describevariable(evar, -1, 0));
2586 			mi[i].changed = FALSE;
2587 			mi[i].response = NOUSERCOM;
2588 			i++;
2589 		}
2590 		me->name = x_("noname");
2591 		me->list = mi;
2592 		me->total = j;
2593 		if (l != 0) me->header = _("Set values (* only)"); else
2594 			me->header = _("Examine values");
2595 		but = TRUE;
2596 		cme = me;
2597 		if (us_popupmenu(&cme, &but, TRUE, -1, -1, 0) == 0)
2598 			us_abortcommand(_("This display does not support popup menus"));
2599 
2600 		/* now deal with changes made */
2601 		search = initobjlist(objaddr, objtype, TRUE);
2602 		if (search == 0)
2603 		{
2604 			us_abortcommand(_("Strange error accessing component"));
2605 			return;
2606 		}
2607 		for(i=0; ;)
2608 		{
2609 			pp = nextobjectlist(&evar, search);
2610 			if (pp == 0) break;
2611 			if ((evar->type&VISARRAY) != 0) continue;
2612 			if (!mi[i].changed) { i++;   continue; }
2613 			l = 0;
2614 			switch (evar->type & VTYPE)
2615 			{
2616 				case VFLOAT:
2617 				case VDOUBLE:   j = castint((float)eatof(mi[i].value));   break;
2618 				case VSHORT:
2619 				case VBOOLEAN:
2620 				case VINTEGER:  j = myatoi(mi[i].value);          break;
2621 				case VCHAR:     j = (INTBIG)*mi[i].value;          break;
2622 				case VSTRING:
2623 					qual = mi[i].value;
2624 					if (*qual == '"' && qual[estrlen(qual)-1] == '"')
2625 					{
2626 						qual[estrlen(qual)-1] = 0;
2627 						qual++;
2628 					}
2629 					j = (INTBIG)qual;
2630 					break;
2631 				default:
2632 					us_abortcommand(_("Cannot change attribute %s: bad type"), pp);
2633 					l++;
2634 					break;
2635 			}
2636 			if (l == 0)
2637 			{
2638 				(void)setval(objaddr, objtype, pp, j, evar->type);
2639 				ttyputmsg(_("Changed attribute %s to %s"), pp, mi[i].value);
2640 			}
2641 			i++;
2642 		}
2643 
2644 		/* free the space */
2645 		for(i=0; i<me->total; i++)
2646 		{
2647 			efree(mi[i].attribute);
2648 			efree(mi[i].value);
2649 		}
2650 		efree((CHAR *)mi);
2651 		efree((CHAR *)me);
2652 		return;
2653 	}
2654 
2655 	/* handle array operations */
2656 	if (namesamen(pp, x_("vector"), l) == 0 && l >= 2)
2657 	{
2658 		if (count < 4)
2659 		{
2660 			ttyputusage(x_("var vector DEST SOURCE1 OPERATOR [SOURCE2]"));
2661 			return;
2662 		}
2663 
2664 		/* get the destination variable */
2665 		if (us_getvar(par[1], &objaddr, &objtype, &pp, &comvar, &aindex))
2666 		{
2667 			us_abortcommand(_("Incorrect variable name: %s"), par[1]);
2668 			return;
2669 		}
2670 		if (aindex >= 0)
2671 		{
2672 			us_abortcommand(_("Use 'var set' to assign values to array entries, not 'var vector'"));
2673 			return;
2674 		}
2675 		if (us_varqualsave == 0) (void)allocstring(&us_varqualsave, pp, us_tool->cluster); else
2676 			(void)reallocstring(&us_varqualsave, pp, us_tool->cluster);
2677 
2678 		/* get the first source variable */
2679 		if (us_getvar(par[2], &objaddr1, &objtype1, &qual1, &comvar, &aindex))
2680 		{
2681 			us_abortcommand(_("Incorrect variable name: %s"), par[2]);
2682 			return;
2683 		}
2684 		if (*qual1 != 0)
2685 		{
2686 			var1 = getval(objaddr1, objtype1, -1, qual1);
2687 			if (var1 == NOVARIABLE)
2688 			{
2689 				us_abortcommand(_("Cannot find first source: %s"), par[2]);
2690 				return;
2691 			}
2692 		} else
2693 		{
2694 			fvar1.addr = objaddr1;
2695 			fvar1.type = objtype1;
2696 			var1 = &fvar1;
2697 		}
2698 		len1 = getlength(var1);
2699 		if (len1 < 0) len1 = 1;
2700 		if (us_expandaddrtypearray(&us_varlimit1, &us_varaddr1, &us_vartype1, len1)) return;
2701 		if ((var1->type&VISARRAY) == 0)
2702 		{
2703 			us_varaddr1[0] = var1->addr;
2704 			us_vartype1[0] = var1->type;
2705 			count1 = 1;
2706 		} else
2707 		{
2708 			if ((var1->type&VTYPE) == VGENERAL)
2709 			{
2710 				for(i=0; i<len1; i += 2)
2711 				{
2712 					us_varaddr1[i/2] = ((INTBIG *)var1->addr)[i];
2713 					us_vartype1[i/2] = ((INTBIG *)var1->addr)[i+1];
2714 				}
2715 				count1 = len1 / 2;
2716 			} else
2717 			{
2718 				for(i=0; i<len1; i++)
2719 				{
2720 					us_varaddr1[i] = ((INTBIG *)var1->addr)[i];
2721 					us_vartype1[i] = var1->type;
2722 				}
2723 				count1 = len1;
2724 			}
2725 		}
2726 
2727 		/* get the operator */
2728 		l = estrlen(pp = par[3]);
2729 		count3 = 0;
2730 		if (namesamen(pp, x_("pattern"), l) == 0 && l >= 1)
2731 		{
2732 			/* set 1 where the pattern matches */
2733 			count3 = count1;
2734 			if (us_expandaddrtypearray(&us_varlimit3, &us_varaddr3, &us_vartype3, count3)) return;
2735 			var = &fvar;
2736 			for(i=0; i<count1; i++)
2737 			{
2738 				fvar.type = us_vartype1[i] & VTYPE;
2739 				fvar.addr = us_varaddr1[i];
2740 				pp = describevariable(var, -1, -1);
2741 				if (us_patternmatch(par[4], pp)) us_varaddr3[i] = 1; else
2742 					us_varaddr3[i] = 0;
2743 				us_vartype3[i] = VINTEGER;
2744 			}
2745 		} else if (namesamen(pp, x_("set"), l) == 0 && l >= 3)
2746 		{
2747 			/* copy the first operand to the destination */
2748 			count3 = count1;
2749 			if (us_expandaddrtypearray(&us_varlimit3, &us_varaddr3, &us_vartype3, count3)) return;
2750 			for(i=0; i<count1; i++)
2751 			{
2752 				us_varaddr3[i] = us_varaddr1[i];
2753 				us_vartype3[i] = us_vartype1[i];
2754 			}
2755 		} else if (namesamen(pp, x_("type"), l) == 0 && l >= 1)
2756 		{
2757 			/* set 1 where the type matches */
2758 			count3 = count1;
2759 			if (us_expandaddrtypearray(&us_varlimit3, &us_varaddr3, &us_vartype3, count3)) return;
2760 			j = us_variabletypevalue(par[4]);
2761 			for(i=0; i<count1; i++)
2762 			{
2763 				if ((us_vartype1[i]&VTYPE) == j) us_varaddr3[i] = 1; else us_varaddr3[i] = 0;
2764 				us_vartype3[i] = VINTEGER;
2765 			}
2766 		} else
2767 		{
2768 			/* two-operand operation: get the second source variable */
2769 			if (count < 4)
2770 			{
2771 				ttyputusage(x_("var vector DEST SOURCE1 OP SOURCE2"));
2772 				return;
2773 			}
2774 
2775 			if (us_getvar(par[4], &objaddr2, &objtype2, &qual2, &comvar, &aindex))
2776 			{
2777 				us_abortcommand(_("Incorrect variable name: %s"), par[4]);
2778 				return;
2779 			}
2780 			if (*qual2 != 0)
2781 			{
2782 				var2 = getval(objaddr2, objtype2, -1, qual2);
2783 				if (var2 == NOVARIABLE)
2784 				{
2785 					us_abortcommand(_("Cannot find second source: %s"), par[4]);
2786 					return;
2787 				}
2788 			} else
2789 			{
2790 				fvar2.addr = objaddr2;
2791 				fvar2.type = objtype2;
2792 				var2 = &fvar2;
2793 			}
2794 			len2 = getlength(var2);
2795 			if (len2 < 0) len2 = 1;
2796 			if (us_expandaddrtypearray(&us_varlimit2, &us_varaddr2, &us_vartype2, len2)) return;
2797 			if ((var2->type&VISARRAY) == 0)
2798 			{
2799 				us_varaddr2[0] = var2->addr;
2800 				us_vartype2[0] = var2->type;
2801 				count2 = 1;
2802 			} else
2803 			{
2804 				if ((var2->type&VTYPE) == VGENERAL)
2805 				{
2806 					for(i=0; i<len2; i += 2)
2807 					{
2808 						us_varaddr2[i/2] = ((INTBIG *)var2->addr)[i];
2809 						us_vartype2[i/2] = ((INTBIG *)var2->addr)[i+1];
2810 					}
2811 					count2 = len2 / 2;
2812 				} else
2813 				{
2814 					for(i=0; i<len2; i++)
2815 					{
2816 						us_varaddr2[i] = ((INTBIG *)var2->addr)[i];
2817 						us_vartype2[i] = var2->type;
2818 					}
2819 					count2 = len2;
2820 				}
2821 			}
2822 
2823 			if (namesamen(pp, x_("concat"), l) == 0 && l >= 1)
2824 			{
2825 				count3 = count1 + count2;
2826 				if (us_expandaddrtypearray(&us_varlimit3, &us_varaddr3, &us_vartype3, count3)) return;
2827 				for(i=0; i<count1; i++)
2828 				{
2829 					us_varaddr3[i] = us_varaddr1[i];
2830 					us_vartype3[i] = us_vartype1[i];
2831 				}
2832 				for(i=0; i<count2; i++)
2833 				{
2834 					us_varaddr3[i+count1] = us_varaddr2[i];
2835 					us_vartype3[i+count1] = us_vartype2[i];
2836 				}
2837 			} else if (namesamen(pp, x_("select"), l) == 0 && l >= 3)
2838 			{
2839 				count3 = 0;
2840 				if (count1 < count2) count2 = count1;
2841 				for(i=0; i<count2; i++)
2842 					if ((us_vartype2[i]&VTYPE) == VINTEGER && us_varaddr2[i] != 0) count3++;
2843 				if (us_expandaddrtypearray(&us_varlimit3, &us_varaddr3, &us_vartype3, count3)) return;
2844 				count3 = 0;
2845 				for(i=0; i<count2; i++)
2846 					if ((us_vartype2[i]&VTYPE) == VINTEGER && us_varaddr2[i] != 0)
2847 				{
2848 					us_varaddr3[count3] = us_varaddr1[i];
2849 					us_vartype3[count3] = us_vartype1[i];
2850 					count3++;
2851 				}
2852 			}
2853 		}
2854 
2855 		/* assign the result to the destination */
2856 		if (count3 == 0)
2857 		{
2858 			/* null array */
2859 			us_varaddr3[0] = -1;
2860 			setval(objaddr, objtype, us_varqualsave, (INTBIG)us_varaddr3, VUNKNOWN|VISARRAY|VDONTSAVE);
2861 			return;
2862 		}
2863 		if (count3 == 1)
2864 		{
2865 			setval(objaddr, objtype, us_varqualsave, us_varaddr3[0], (us_vartype3[0]&VTYPE)|VDONTSAVE);
2866 		} else
2867 		{
2868 			for(i=1; i<count3; i++)
2869 				if ((us_vartype3[i-1]&VTYPE) != (us_vartype3[i]&VTYPE)) break;
2870 			if (count3 > 1 && i < count3)
2871 			{
2872 				/* general array needed because not all entries are the same type */
2873 				newarray = (INTBIG *)emalloc(count3*2 * SIZEOFINTBIG, el_tempcluster);
2874 				if (newarray == 0) return;
2875 				for(i=0; i<count3; i++)
2876 				{
2877 					newarray[i*2] = us_varaddr3[i];
2878 					newarray[i*2+1] = us_vartype3[i];
2879 				}
2880 				setval(objaddr, objtype, us_varqualsave, (INTBIG)newarray,
2881 					VGENERAL|VISARRAY|((count3*2)<<VLENGTHSH)|VDONTSAVE);
2882 				efree((CHAR *)newarray);
2883 			} else
2884 			{
2885 				/* uniform array */
2886 				setval(objaddr, objtype, us_varqualsave, (INTBIG)us_varaddr3,
2887 					(us_vartype3[0]&VTYPE)|VISARRAY|(count3<<VLENGTHSH)|VDONTSAVE);
2888 			}
2889 		}
2890 		return;
2891 	}
2892 
2893 	/* handle the setting and modifying options */
2894 	function = 0;
2895 	if (namesamen(pp, x_("set"), l) == 0 && l >= 1) function = 's';
2896 	if (namesamen(pp, x_("+"), l) == 0 && l >= 1) function = '+';
2897 	if (namesamen(pp, x_("-"), l) == 0 && l >= 1) function = '-';
2898 	if (namesamen(pp, x_("*"), l) == 0 && l >= 1) function = '*';
2899 	if (namesamen(pp, x_("/"), l) == 0 && l >= 1) function = '/';
2900 	if (namesamen(pp, x_("mod"), l) == 0 && l >= 1) function = 'm';
2901 	if (namesamen(pp, x_("and"), l) == 0 && l >= 1) function = 'a';
2902 	if (namesamen(pp, x_("or"), l) == 0 && l >= 1) function = 'o';
2903 	if (namesamen(pp, x_("|"), l) == 0 && l >= 1) function = '|';
2904 	if (function == 0)
2905 	{
2906 		ttyputusage(x_("var [examine|set|delete|OP] VARIABLE MOD"));
2907 		ttyputmsg(x_("OP: + - * / mod | or and"));
2908 		return;
2909 	}
2910 
2911 	/* make sure there is a variable name to set/modify */
2912 	if (count <= 1)
2913 	{
2914 		count = ttygetparam(x_("Variable: "), &us_varvsp, MAXPARS-1, &par[1]) + 1;
2915 		if (count == 1)
2916 		{
2917 			us_abortedmsg();
2918 			return;
2919 		}
2920 	}
2921 	if (us_getvar(par[1], &objaddr, &objtype, &qual, &comvar, &aindex))
2922 	{
2923 		us_abortcommand(_("Incorrect variable name: %s"), par[1]);
2924 		return;
2925 	}
2926 	estrcpy(qualname, qual);
2927 	var = getval(objaddr, objtype, -1, qualname);
2928 	if (var != NOVARIABLE)
2929 	{
2930 		newtype = var->type;
2931 		TDCOPY(newdescript, var->textdescript);
2932 
2933 		/* do some pre-computation on existing variables */
2934 		if ((newtype&VCANTSET) != 0)
2935 		{
2936 			us_abortcommand(_("%s is not a settable variable"), par[1]);
2937 			return;
2938 		}
2939 		oldlen = getlength(var);
2940 		if (aindex >= 0 && (newtype&VISARRAY) == 0)
2941 		{
2942 			us_abortcommand(_("%s is not an array: cannot index it"), par[1]);
2943 			return;
2944 		}
2945 		if (aindex < 0 && (newtype&VISARRAY) != 0)
2946 		{
2947 			ttyputmsg(_("Warning: %s was an array: now scalar"), par[1]);
2948 			newtype &= ~VISARRAY;
2949 		}
2950 	}
2951 
2952 	/* make sure there is a value to set/adjust */
2953 	if (count <= 2)
2954 	{
2955 		count = ttygetparam(M_("Value: "), &us_varvalp, MAXPARS-2, &par[2]) + 2;
2956 		if (count == 2)
2957 		{
2958 			us_abortedmsg();
2959 			return;
2960 		}
2961 	}
2962 
2963 	/* make sure modifications are done on the right types */
2964 	if (function != 's')
2965 	{
2966 		/* operation is "+", "-", "*", "/", "m", "a", "o", "|" */
2967 		if (var == NOVARIABLE)
2968 		{
2969 			us_abortcommand(_("Variable does not exist: cannot be modified"));
2970 			return;
2971 		}
2972 		if (aindex < 0 && (newtype&VISARRAY) != 0)
2973 		{
2974 			us_abortcommand(_("%s is an array: must index it"), par[1]);
2975 			return;
2976 		}
2977 		if (aindex < 0) oldaddr = var->addr; else
2978 		{
2979 			if ((newtype&VISARRAY) == 0)
2980 			{
2981 				us_abortcommand(_("%s is not an array: cannot index it"), par[1]);
2982 				return;
2983 			}
2984 			if (aindex >= oldlen)
2985 			{
2986 				us_abortcommand(_("%s has only %ld entries, cannot use %ld"), par[1], oldlen, aindex);
2987 				return;
2988 			}
2989 			if ((newtype&VTYPE) == VDOUBLE)
2990 				oldaddr = (INTBIG)(((double *)var->addr)[aindex]); else
2991 					oldaddr = ((INTBIG *)var->addr)[aindex];
2992 		}
2993 		if (function != '|')
2994 		{
2995 			/* operation is "+", "-", "*", "/", "m", "a", "o" */
2996 			if ((newtype&VTYPE) != VINTEGER && (newtype&VTYPE) != VFLOAT &&
2997 				(newtype&VTYPE) != VDOUBLE && (newtype&VTYPE) != VFRACT &&
2998 				(newtype&VTYPE) != VSHORT)
2999 			{
3000 				us_abortcommand(_("Can only do arithmetic on numbers"));
3001 				return;
3002 			}
3003 
3004 			if ((newtype&VTYPE) == VFLOAT || (newtype&VTYPE) == VDOUBLE)
3005 			{
3006 				oldfloat = castfloat(oldaddr);
3007 			} else if ((newtype&VTYPE) == VINTEGER)
3008 			{
3009 				/* might be able to re-cast integers as floats */
3010 				for(pp = par[2]; *pp != 0; pp++) if (*pp == '.')
3011 				{
3012 					if ((newtype&VISARRAY) != 0)
3013 					{
3014 						us_abortcommand(_("Cannot change array to floating point"));
3015 						return;
3016 					}
3017 					newtype = (newtype & ~VTYPE) | VFLOAT;
3018 					oldfloat = (float)oldaddr;
3019 					break;
3020 				}
3021 			}
3022 			if ((newtype&VTYPE) != VINTEGER && (function == 'o' || function == 'a' || function == 'm'))
3023 			{
3024 				us_abortcommand(_("Must do bit or modulo arithmetic on integers"));
3025 				return;
3026 			}
3027 		} else if ((newtype&VTYPE) != VSTRING)
3028 		{
3029 			us_abortcommand(_("Can only do concatentation on strings"));
3030 			return;
3031 		}
3032 	} else
3033 	{
3034 		/* setting a nonexistent variable: determine the type */
3035 		if (var == NOVARIABLE || (var->type&VISARRAY) == 0)
3036 		{
3037 			/* establish the type of this parameter if it is being set */
3038 			getsimpletype(par[2], &newtype, &newaddr, 0);
3039 			if (objtype == VARCINST) geom = ((ARCINST *)objaddr)->geom; else
3040 				if (objtype == VNODEINST) geom = ((NODEINST *)objaddr)->geom; else
3041 					geom = NOGEOM;
3042 			TDCLEAR(newdescript);
3043 			defaulttextdescript(newdescript, geom);
3044 		}
3045 	}
3046 
3047 	/* get options on how to change the variable */
3048 	disppart = 0;
3049 	if (count >= 4)
3050 	{
3051 		l = estrlen(pp = par[3]);
3052 		if (namesamen(pp, x_("display"), l) == 0 && l >= 1)
3053 		{
3054 			newtype |= VDISPLAY;
3055 			disppart = VTDISPLAYVALUE;
3056 			us_figurevariableplace(newdescript, count-4, &par[4]);
3057 			l = 0;
3058 		} else if (namesamen(pp, x_("na-va-display"), l) == 0 && l >= 1)
3059 		{
3060 			newtype |= VDISPLAY;
3061 			disppart = VTDISPLAYNAMEVALUE;
3062 			us_figurevariableplace(newdescript, count-4, &par[4]);
3063 			l = 0;
3064 		} else if (namesamen(pp, x_("in-na-va-display"), l) == 0 && l >= 3)
3065 		{
3066 			newtype |= VDISPLAY;
3067 			disppart = VTDISPLAYNAMEVALINH;
3068 			if ((objtype&VTYPE) != VNODEPROTO)
3069 			{
3070 				ttyputmsg(_("%s is allowed for cells only, changing to na-va-display"), pp);
3071 				disppart = VTDISPLAYNAMEVALUE;
3072 			}
3073 			us_figurevariableplace(newdescript, count-4, &par[4]);
3074 			l = 0;
3075 		} else if (namesamen(pp, x_("inall-na-va-display"), l) == 0 && l >= 3)
3076 		{
3077 			newtype |= VDISPLAY;
3078 			disppart = VTDISPLAYNAMEVALINHALL;
3079 			if ((objtype&VTYPE) != VNODEPROTO)
3080 			{
3081 				ttyputmsg(_("%s is allowed for cells only, changing to na-va-display"), pp);
3082 				disppart = VTDISPLAYNAMEVALUE;
3083 			}
3084 			us_figurevariableplace(newdescript, count-4, &par[4]);
3085 			l = 0;
3086 		} else if (namesamen(pp, x_("lisp"), l) == 0 && l >= 1)
3087 		{
3088 			if (aindex < 0 || var == NOVARIABLE) newtype = (newtype & ~(VCODE1|VCODE2)) | VLISP;
3089 			l = 0;
3090 		} else if (namesamen(pp, x_("tcl"), l) == 0 && l >= 1)
3091 		{
3092 			if (aindex < 0 || var == NOVARIABLE) newtype = (newtype & ~(VCODE1|VCODE2)) | VTCL;
3093 			l = 0;
3094 		} else if (namesamen(pp, x_("java"), l) == 0 && l >= 1)
3095 		{
3096 			if (aindex < 0 || var == NOVARIABLE) newtype = (newtype & ~(VCODE1|VCODE2)) | VJAVA;
3097 			l = 0;
3098 		} else if (namesamen(pp, x_("temporary"), l) == 0 && l >= 1)
3099 		{
3100 			if (aindex < 0 || var == NOVARIABLE) newtype |= VDONTSAVE;
3101 			l = 0;
3102 		} else if (namesamen(pp, x_("fractional"), l) == 0 && l >= 1)
3103 		{
3104 			if (aindex < 0 || var == NOVARIABLE) newtype = (newtype & ~VTYPE) | VFRACT;
3105 			l = 0;
3106 		} else if (namesamen(pp, x_("float"), l) == 0 && l >= 1)
3107 		{
3108 			if (aindex < 0 || var == NOVARIABLE) newtype = (newtype & ~VTYPE) | VFLOAT;
3109 			l = 0;
3110 		} else if (namesamen(pp, x_("cannot-change"), l) == 0 && l >= 1)
3111 		{
3112 			if (aindex < 0 || var == NOVARIABLE) newtype |= VCANTSET;
3113 			l = 0;
3114 		}
3115 		if (l > 0)
3116 		{
3117 			ttyputusage(x_("var set VARIABLE [OPTION]"));
3118 			ttyputusage(x_("OPTION: lisp|tcl|java|display|temporary|fractional|float|cannot-change"));
3119 			return;
3120 		}
3121 	}
3122 
3123 	/* do the modification */
3124 	switch (function)
3125 	{
3126 		case '+':
3127 			if ((newtype&VTYPE) == VINTEGER) newval = oldaddr + myatoi(par[2]); else
3128 				if ((newtype&VTYPE) == VFRACT) newval = oldaddr + atofr(par[2]); else
3129 					newval = castint(oldfloat + (float)eatof(par[2]));
3130 			break;
3131 		case '-':
3132 			if ((newtype&VTYPE) == VINTEGER) newval = oldaddr - myatoi(par[2]); else
3133 				if ((newtype&VTYPE) == VFRACT) newval = oldaddr - atofr(par[2]); else
3134 					newval = castint(oldfloat - (float)eatof(par[2]));
3135 			break;
3136 		case '*':
3137 			if ((newtype&VTYPE) == VINTEGER) newval = oldaddr * myatoi(par[2]); else
3138 				if ((newtype&VTYPE) == VFRACT) newval = muldiv(oldaddr, atofr(par[2]), WHOLE); else
3139 					newval = castint(oldfloat * (float)eatof(par[2]));
3140 			break;
3141 		case '/':
3142 			if ((newtype&VTYPE) == VINTEGER)
3143 			{
3144 				i = myatoi(par[2]);
3145 				if (i != 0) newval = oldaddr / i; else
3146 				{
3147 					ttyputerr(_("Attempt to divide by zero"));
3148 					newval = 0;
3149 				}
3150 			} else if ((newtype&VTYPE) == VFRACT)
3151 			{
3152 				i = atofr(par[2]);
3153 				if (i != 0) newval = muldiv(oldaddr, WHOLE, i); else
3154 				{
3155 					ttyputerr(_("Attempt to divide by zero"));
3156 					newval = 0;
3157 				}
3158 			} else
3159 			{
3160 				oldden = (float)eatof(par[2]);
3161 				if (oldden != 0.0)
3162 					newval = castint((float)(oldfloat / oldden)); else
3163 				{
3164 					ttyputerr(_("Attempt to divide by zero"));
3165 					newval = castint(0.0);
3166 				}
3167 			}
3168 			break;
3169 		case 'm':
3170 			i = myatoi(par[2]);
3171 			if (i != 0) newval = oldaddr % i; else
3172 			{
3173 				ttyputerr(_("Attempt to modulo by zero"));
3174 				newval = 0;
3175 			}
3176 			break;
3177 		case 'a':
3178 			newval = oldaddr & myatoi(par[2]);   break;
3179 		case 'o':
3180 			newval = oldaddr | myatoi(par[2]);   break;
3181 		case '|':
3182 			infstr = initinfstr();
3183 			addstringtoinfstr(infstr, (CHAR *)oldaddr);
3184 			addstringtoinfstr(infstr, par[2]);
3185 			newval = (INTBIG)returninfstr(infstr);
3186 			break;
3187 		case 's':
3188 			if ((newtype&VTYPE) == VINTEGER || (newtype&VTYPE) == VSHORT || (newtype&VTYPE) == VBOOLEAN)
3189 				newval = myatoi(par[2]); else
3190 					if ((newtype&VTYPE) == VFRACT) newval = atofr(par[2]); else
3191 						if ((newtype&VTYPE) == VFLOAT || (newtype&VTYPE) == VDOUBLE)
3192 							newval = castint((float)eatof(par[2])); else
3193 								newval = (INTBIG)par[2];
3194 			break;
3195 	}
3196 
3197 	/* ensure that command interpreter variables are always temporary */
3198 	if (comvar) newtype |= VDONTSAVE;
3199 
3200 	/* signal start of change to nodes and arcs */
3201 	if (objtype == VNODEINST || objtype == VARCINST)
3202 	{
3203 		us_pushhighlight();
3204 		us_clearhighlightcount();
3205 		startobjectchange(objaddr, objtype);
3206 	} else if (objtype == VNODEPROTO)
3207 	{
3208 		if (var != NOVARIABLE) us_undrawcellvariable(var, (NODEPROTO *)objaddr);
3209 	}
3210 
3211 	/* change the variable */
3212 	if (aindex < 0) res = setval(objaddr, objtype, qualname, newval, newtype); else
3213 	{
3214 		if (var == NOVARIABLE)
3215 		{
3216 			/* creating array variable */
3217 			newarray = emalloc(((aindex+1) * SIZEOFINTBIG), el_tempcluster);
3218 			if (newarray == 0)
3219 			{
3220 				ttyputnomemory();
3221 				return;
3222 			}
3223 			for(j=0; j<=aindex; j++) newarray[j] = newval;
3224 			newtype |= VISARRAY | ((aindex+1)<<VLENGTHSH);
3225 			res = setval(objaddr, objtype, qualname, (INTBIG)newarray, newtype);
3226 			efree((CHAR *)newarray);
3227 		} else if (oldlen <= aindex)
3228 		{
3229 			/* extend existing array variable */
3230 			newarray = emalloc(((aindex+1) * SIZEOFINTBIG), el_tempcluster);
3231 			if (newarray == 0)
3232 			{
3233 				ttyputnomemory();
3234 				return;
3235 			}
3236 			if ((newtype&VTYPE) == VSTRING)
3237 			{
3238 				for(j=0; j<oldlen; j++)
3239 					(void)allocstring((CHAR **)&newarray[j],
3240 						(CHAR *)((INTBIG *)var->addr)[j], el_tempcluster);
3241 				for(j=oldlen; j<aindex; j++) newarray[j] = (INTBIG)nullstr;
3242 			} else
3243 			{
3244 				for(j=0; j<oldlen; j++) newarray[j] = ((INTBIG *)var->addr)[j];
3245 				for(j=oldlen; j<aindex; j++) newarray[j] = 0;
3246 			}
3247 			newarray[aindex] = newval;
3248 			newtype = (newtype & ~VLENGTH) | ((aindex+1)<<VLENGTHSH);
3249 			res = setval(objaddr, objtype, qualname, (INTBIG)newarray, newtype);
3250 			if ((newtype&VTYPE) == VSTRING)
3251 				for(j=0; j<oldlen; j++) efree((CHAR *)newarray[j]);
3252 			efree((CHAR *)newarray);
3253 		} else
3254 		{
3255 			if (setind(objaddr, objtype, qualname, aindex, newval))
3256 				res = NOVARIABLE; else res = (VARIABLE *)1;
3257 		}
3258 	}
3259 	if (res == NOVARIABLE)
3260 	{
3261 		ttyputnomemory();
3262 		return;
3263 	}
3264 	if (res != (VARIABLE *)1)
3265 	{
3266 		TDCOPY(res->textdescript, newdescript);
3267 		TDSETDISPPART(res->textdescript, disppart);
3268 	}
3269 
3270 	/* signal end of change to nodes and arcs */
3271 	if (objtype == VNODEINST || objtype == VARCINST)
3272 	{
3273 		endobjectchange(objaddr, objtype);
3274 		us_pophighlight(FALSE);
3275 	} else if (objtype == VNODEPROTO)
3276 	{
3277 		if (res != NOVARIABLE) us_drawcellvariable(res, (NODEPROTO *)objaddr);
3278 	}
3279 }
3280 
us_view(INTBIG count,CHAR * par[])3281 void us_view(INTBIG count, CHAR *par[])
3282 {
3283 	REGISTER CHAR *pp, *abbrev, *pt;
3284 	REGISTER INTBIG i, l;
3285 	REGISTER BOOLEAN found;
3286 	REGISTER LIBRARY *lib;
3287 	REGISTER NODEPROTO *np;
3288 	REGISTER VARIABLE *var;
3289 	REGISTER VIEW *nv;
3290 	REGISTER WINDOWPART *w;
3291 	REGISTER EDITOR *ed;
3292 	REGISTER void *infstr;
3293 	CHAR line[10];
3294 
3295 	if (count == 0)
3296 	{
3297 		ttyputusage(x_("view new | delete | change | frame"));
3298 		return;
3299 	}
3300 
3301 	l = estrlen(pp = par[0]);
3302 
3303 	if (namesamen(pp, x_("new"), l) == 0 && l >= 1)
3304 	{
3305 		if (count < 2)
3306 		{
3307 			ttyputusage(x_("view new NEWVIEWNAME [ABBREVIATION [TYPE]]"));
3308 			return;
3309 		}
3310 
3311 		pp = par[1];
3312 		nv = getview(pp);
3313 
3314 		/* special case for multi-page schematics */
3315 		if (namesamen(pp, x_("schematic-page-"), 15) == 0)
3316 		{
3317 			/* check validity of abbreviation for schematic page view */
3318 			pt = &pp[15];
3319 			if (!isanumber(&pp[15]))
3320 			{
3321 				us_abortcommand(_("Page number must follow 'schematics-page-'"));
3322 				return;
3323 			}
3324 			if (nv != NOVIEW)
3325 			{
3326 				ttyputverbose(M_("Schematic page %s already exists"), &pp[15]);
3327 				return;
3328 			}
3329 		}
3330 
3331 		/* make sure name is unique */
3332 		if (nv != NOVIEW)
3333 		{
3334 			us_abortcommand(_("Already a view called '%s'"), nv->viewname);
3335 			return;
3336 		}
3337 
3338 		if (count >= 3)
3339 		{
3340 			/* get the short view name */
3341 			abbrev = par[2];
3342 			if (namesamen(pp, x_("schematic-page-"), 15) == 0)
3343 			{
3344 				if ((abbrev[0] != 'p' && abbrev[0] != 'P') || estrcmp(&pp[15], &abbrev[1]) != 0)
3345 				{
3346 					us_abortcommand(_("Incorrect abbreviation for schematic page"));
3347 					count = 2;
3348 				}
3349 			} else
3350 			{
3351 				/* make sure the abbreviation is not confused with schematic one */
3352 				if ((abbrev[0] == 'p' || abbrev[0] == 'P') && isanumber(&abbrev[1]))
3353 				{
3354 					us_abortcommand(_("Can only use 'Pnumber' abbreviation for multipage schematic views"));
3355 					return;
3356 				}
3357 			}
3358 		}
3359 		if (count < 3)
3360 		{
3361 			/* generate a short view name */
3362 			if (namesamen(pp, x_("schematic-page-"), 15) == 0)
3363 			{
3364 				/* special case for schematics pages */
3365 				abbrev = (CHAR *)emalloc((estrlen(&pp[15])+2) * SIZEOFCHAR, el_tempcluster);
3366 				abbrev[0] = 'p';
3367 				(void)estrcpy(&abbrev[1], &pp[15]);
3368 			} else
3369 			{
3370 				/* simply find initial unique letters */
3371 				for(i=0; pp[i] != 0; i++)
3372 				{
3373 					for(nv = el_views; nv != NOVIEW; nv = nv->nextview)
3374 						if (namesamen(nv->sviewname, pp, i+1) == 0) break;
3375 					if (nv == NOVIEW) break;
3376 				}
3377 				abbrev = (CHAR *)emalloc((i+2) * SIZEOFCHAR, el_tempcluster);
3378 				(void)estrncpy(abbrev, pp, i+1);
3379 				abbrev[i+1] = 0;
3380 			}
3381 			ttyputverbose(M_("Using '%s' as abbreviation"), abbrev);
3382 		}
3383 
3384 		/* see if the view already exists */
3385 		nv = getview(pp);
3386 		if (nv != NOVIEW)
3387 		{
3388 			if (namesame(nv->sviewname, abbrev) != 0)
3389 				ttyputmsg(_("View %s already exists with abbreviation %s"), nv->viewname, nv->sviewname);
3390 			return;
3391 		}
3392 
3393 		/* create the view */
3394 		nv = newview(pp, abbrev);
3395 		if (nv == NOVIEW)
3396 		{
3397 			us_abortcommand(_("Could not create the new view"));
3398 			return;
3399 		}
3400 
3401 		/* get type of view */
3402 		if (count >= 4)
3403 		{
3404 			pp = par[3];
3405 			if (namesamen(pp, x_("text"), estrlen(pp)) == 0) nv->viewstate |= TEXTVIEW;
3406 		}
3407 		ttyputverbose(M_("View '%s' created"), pp);
3408 
3409 		/* clean up */
3410 		if (count < 3) efree(abbrev);
3411 		return;
3412 	}
3413 
3414 	if (namesamen(pp, x_("delete"), l) == 0 && l >= 1)
3415 	{
3416 		if (count < 2)
3417 		{
3418 			ttyputusage(x_("view delete VIEWNAME"));
3419 			return;
3420 		}
3421 
3422 		/* make sure name exists */
3423 		nv = getview(par[1]);
3424 		if (nv == NOVIEW)
3425 		{
3426 			us_abortcommand(_("Unknown view: %s"), par[1]);
3427 			return;
3428 		}
3429 
3430 		if ((nv->viewstate&PERMANENTVIEW) != 0)
3431 		{
3432 			us_abortcommand(_("Cannot delete important views like %s"), nv->viewname);
3433 			return;
3434 		}
3435 
3436 		/* make sure no cells in any library have this view */
3437 		found = FALSE;
3438 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
3439 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3440 				if (np->cellview == nv)
3441 		{
3442 			if (!found)
3443 			{
3444 				us_abortcommand(_("Must first remove these cells in view %s"), nv->viewname);
3445 				found = TRUE;
3446 			}
3447 			ttyputmsg(x_("   %s"), describenodeproto(np));
3448 		}
3449 		if (found) return;
3450 
3451 		/* delete the view */
3452 		if (killview(nv)) ttyputerr(_("Problem deleting view"));
3453 			else ttyputverbose(M_("View '%s' deleted"), par[1]);
3454 		return;
3455 	}
3456 
3457 	if (namesamen(pp, x_("change"), l) == 0 && l >= 1)
3458 	{
3459 		if (count != 3)
3460 		{
3461 			ttyputusage(x_("view change CELL VIEW"));
3462 			return;
3463 		}
3464 
3465 		/* get cell */
3466 		np = getnodeproto(par[1]);
3467 		if (np == NONODEPROTO || np->primindex != 0)
3468 		{
3469 			us_abortcommand(_("'%s' is not a cell"), par[1]);
3470 			return;
3471 		}
3472 
3473 		/* disallow change if lock is on */
3474 		if (us_cantedit(np, NONODEINST, TRUE)) return;
3475 
3476 		/* get view */
3477 		nv = getview(par[2]);
3478 		if (nv == NOVIEW)
3479 		{
3480 			us_abortcommand(_("Unknown view type: %s"), par[2]);
3481 			return;
3482 		}
3483 
3484 		if (!changecellview(np, nv))
3485 		{
3486 			ttyputverbose(M_("Cell %s is now %s"), par[1], describenodeproto(np));
3487 
3488 			/* set current nodeproto to itself to redisplay its name */
3489 			if (np == getcurcell())
3490 				(void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
3491 
3492 			/* update status display if necessary */
3493 			for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
3494 			{
3495 				if (w->curnodeproto != np) continue;
3496 
3497 				/* if this window is textual, change the header string */
3498 				if ((w->state&WINDOWTYPE) == TEXTWINDOW)
3499 				{
3500 					ed = w->editor;
3501 					if (ed != NOEDITOR)
3502 					{
3503 						(void)reallocstring(&ed->header, describenodeproto(np), us_tool->cluster);
3504 						(*w->redisphandler)(w);
3505 					}
3506 				}
3507 				us_setcellname(w);
3508 			}
3509 			if (us_curnodeproto != NONODEPROTO && us_curnodeproto == np)
3510 			{
3511 				us_curnodeproto = NONODEPROTO;
3512 				us_setnodeproto(np);
3513 			}
3514 		}
3515 		return;
3516 	}
3517 
3518 	if (namesamen(pp, x_("frame"), l) == 0 && l >= 1)
3519 	{
3520 		/* get cell */
3521 		np = us_needcell();
3522 		if (np == NONODEPROTO) return;
3523 
3524 		if (count == 1)
3525 		{
3526 			/* report the frame in use here */
3527 			var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING, el_schematic_page_size_key);
3528 			if (var == NOVARIABLE)
3529 			{
3530 				ttyputmsg(M_("This cell has no frame"));
3531 				return;
3532 			}
3533 			pt = (CHAR *)var->addr;
3534 			infstr = initinfstr();
3535 			switch (*pt)
3536 			{
3537 				case 'x': case 'X': addtoinfstr(infstr, 'X');   break;
3538 				case 'a': case 'A': addtoinfstr(infstr, 'A');   break;
3539 				case 'b': case 'B': addtoinfstr(infstr, 'B');   break;
3540 				case 'c': case 'C': addtoinfstr(infstr, 'C');   break;
3541 				case 'd': case 'D': addtoinfstr(infstr, 'D');   break;
3542 				case 'e': case 'E': addtoinfstr(infstr, 'E');   break;
3543 			}
3544 			pt++;
3545 			while (*pt != 0)
3546 			{
3547 				if (*pt == 'v' || *pt == 'V') addstringtoinfstr(infstr, M_(", vertical"));
3548 				if (*pt == 'n' || *pt == 'N') addstringtoinfstr(infstr, M_(", no title box"));
3549 				pt++;
3550 			}
3551 			ttyputmsg(M_("This cell has a frame of size %s"), returninfstr(infstr));
3552 			return;
3553 		}
3554 
3555 		/* set the frame size */
3556 		l = estrlen(pp = par[1]);
3557 		if (namesamen(pp, x_("none"), l) == 0 && l >= 1)
3558 		{
3559 			if (getvalkey((INTBIG)np, VNODEPROTO, VSTRING, el_schematic_page_size_key) != NOVARIABLE)
3560 				(void)delvalkey((INTBIG)np, VNODEPROTO, el_schematic_page_size_key);
3561 			return;
3562 		}
3563 		if (namesamen(pp, x_("title-only"), l) == 0 && l >= 1)
3564 		{
3565 			estrcpy(line, x_("x"));
3566 			(void)setvalkey((INTBIG)np, VNODEPROTO, el_schematic_page_size_key, (INTBIG)line, VSTRING);
3567 			return;
3568 		}
3569 		line[0] = 0;
3570 		if (namesamen(pp, x_("A"), l) == 0 && l >= 1) estrcat(line, x_("a")); else
3571 		if (namesamen(pp, x_("B"), l) == 0 && l >= 1) estrcat(line, x_("b")); else
3572 		if (namesamen(pp, x_("C"), l) == 0 && l >= 1) estrcat(line, x_("c")); else
3573 		if (namesamen(pp, x_("D"), l) == 0 && l >= 1) estrcat(line, x_("d")); else
3574 		if (namesamen(pp, x_("E"), l) == 0 && l >= 1) estrcat(line, x_("e")); else
3575 		if (namesamen(pp, x_("Half-A"), l) == 0 && l >= 1) estrcat(line, x_("h")); else
3576 		{
3577 			ttyputbadusage(x_("view frame"));
3578 			return;
3579 		}
3580 		for(i=2; i<count; i++)
3581 		{
3582 			if (namesamen(par[i], x_("vertical"), estrlen(par[i])) == 0)
3583 				estrcat(line, x_("v"));
3584 			if (namesamen(par[i], x_("no-title"), estrlen(par[i])) == 0)
3585 				estrcat(line, x_("n"));
3586 		}
3587 		(void)setvalkey((INTBIG)np, VNODEPROTO, el_schematic_page_size_key, (INTBIG)line, VSTRING);
3588 		return;
3589 	}
3590 	ttyputbadusage(x_("view"));
3591 }
3592 
us_visiblelayers(INTBIG count,CHAR * par[])3593 void us_visiblelayers(INTBIG count, CHAR *par[])
3594 {
3595 	CHAR line[100];
3596 	REGISTER INTBIG i, j, val;
3597 	REGISTER BOOLEAN defstate, noprint, addstate;
3598 	REGISTER INTBIG fun;
3599 	REGISTER CHAR *ch, *la;
3600 
3601 	/* if the user wants every layer, do it */
3602 	if (us_needwindow()) return;
3603 	noprint = FALSE;
3604 	if (count > 0)
3605 	{
3606 		if (count > 1 && namesame(par[1], x_("no-list")) == 0) noprint = TRUE;
3607 		if (estrcmp(par[0], x_("*")) == 0)
3608 		{
3609 			/* save highlighting */
3610 			us_pushhighlight();
3611 			us_clearhighlightcount();
3612 			startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
3613 
3614 			for(i=0; i<el_curtech->layercount; i++)
3615 			{
3616 				if ((el_curtech->layers[i]->colstyle&INVISIBLE) == 0) continue;
3617 				(void)setval((INTBIG)el_curtech->layers[i], VGRAPHICS, x_("style"),
3618 					el_curtech->layers[i]->colstyle & ~INVISIBLE, VSHORT);
3619 			}
3620 
3621 			/* restore highlighting and redisplay */
3622 			endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
3623 			us_pophighlight(FALSE);
3624 		} else
3625 		{
3626 			/* handle specific request for visible layers */
3627 			defstate = TRUE;
3628 			addstate = FALSE;
3629 			if (par[0][0] == '*' && par[0][1] == '-' && par[0][2] != 0)
3630 			{
3631 				par[0] += 2;
3632 				defstate = FALSE;
3633 			} else if (par[0][0] == '-' && par[0][1] != 0)
3634 			{
3635 				par[0] += 1;
3636 				defstate = FALSE;
3637 				addstate = TRUE;
3638 			} else if (par[0][0] == '+' && par[0][1] != 0)
3639 			{
3640 				par[0] += 1;
3641 				addstate = TRUE;
3642 			}
3643 
3644 			/* collect all of the layer letters */
3645 			(void)estrcpy(line, x_(""));
3646 			for(i=0; i<el_curtech->layercount; i++)
3647 				(void)estrcat(line, us_layerletters(el_curtech, i));
3648 
3649 			/* now see if the user-requested layers are valid names */
3650 			for(ch = par[0]; *ch != 0 && *ch != '('; ch++)
3651 			{
3652 				for(i=0; line[i] != 0; i++) if (*ch == line[i]) break;
3653 				if (line[i] == 0)
3654 				{
3655 					us_abortcommand(_("No such layer: %c"), *ch);
3656 					return;
3657 				}
3658 			}
3659 
3660 			/* initially set all layers to default if not adding */
3661 			if (!addstate)
3662 			{
3663 				for(i=0; i<el_curtech->layercount; i++)
3664 				{
3665 					if (!defstate)
3666 						el_curtech->layers[i]->colstyle &= ~INVTEMP; else
3667 							el_curtech->layers[i]->colstyle |= INVTEMP;
3668 				}
3669 			}
3670 
3671 			/* set the changes */
3672 			for(i=0; i<el_curtech->layercount; i++)
3673 			{
3674 				la = us_layerletters(el_curtech, i);
3675 				for(j=0; la[j] != 0; j++)
3676 					for(ch = par[0]; *ch != 0 && *ch != '('; ch++)
3677 						if (*ch == la[j])
3678 				{
3679 					if (!defstate) el_curtech->layers[i]->colstyle |= INVTEMP; else
3680 						el_curtech->layers[i]->colstyle &= ~INVTEMP;
3681 				}
3682 			}
3683 
3684 			/* save highlighting */
3685 			us_pushhighlight();
3686 			us_clearhighlightcount();
3687 			startobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
3688 
3689 			/* make the changes */
3690 			for(i=0; i<el_curtech->layercount; i++)
3691 			{
3692 				val = el_curtech->layers[i]->colstyle;
3693 				if ((val&(INVTEMP|INVISIBLE)) == INVTEMP)
3694 				{
3695 					(void)setval((INTBIG)el_curtech->layers[i], VGRAPHICS,
3696 						x_("style"), val | INVISIBLE, VSHORT);
3697 					continue;
3698 				}
3699 				if ((val&(INVTEMP|INVISIBLE)) == INVISIBLE)
3700 				{
3701 					(void)setval((INTBIG)el_curtech->layers[i], VGRAPHICS,
3702 						x_("style"), val & ~INVISIBLE, VSHORT);
3703 					continue;
3704 				}
3705 			}
3706 
3707 			/* restore highlighting */
3708 			endobjectchange((INTBIG)el_curwindowpart, VWINDOWPART);
3709 			us_pophighlight(FALSE);
3710 		}
3711 	}
3712 
3713 	/* tell which layers are visible */
3714 	if (noprint) return;
3715 	j = 0;
3716 	for(i=0; i<el_curtech->layercount; i++)
3717 	{
3718 		if ((el_curtech->layers[i]->colstyle&INVISIBLE) != 0) continue;
3719 		if (j++ == 0) ttyputmsg(M_("Visible layers:"));
3720 		ch = us_layerletters(el_curtech, i);
3721 		fun = layerfunction(el_curtech, i);
3722 		if (*ch == 0) ttyputmsg(M_("Layer %s"), layername(el_curtech, i)); else
3723 			ttyputmsg(M_("Layer %s, letters %s%s"), layername(el_curtech, i), us_layerletters(el_curtech, i),
3724 				(fun&(LFTRANS1|LFTRANS2|LFTRANS3|LFTRANS4|LFTRANS5)) != 0 ? M_(" (transparent)") : x_(""));
3725 	}
3726 	if (j == 0) ttyputmsg(M_("No visible layers"));
3727 }
3728 
us_wpopcharhandler(INTSML chr,INTBIG special)3729 static BOOLEAN us_wpopcharhandler(INTSML chr, INTBIG special)
3730 {
3731 	return((*us_wpop->charhandler)(us_wpop, chr, special));
3732 }
3733 
us_wpopbuttonhandler(INTBIG x,INTBIG y,INTBIG but)3734 static BOOLEAN us_wpopbuttonhandler(INTBIG x, INTBIG y, INTBIG but)
3735 {
3736 	if (us_wpop->buttonhandler != 0) (*us_wpop->buttonhandler)(us_wpop, but, x, y);
3737 	return(FALSE);
3738 }
3739