1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrcomln.c
6 * User interface tool: command handler for L through N
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "egraphics.h"
34 #include "usr.h"
35 #include "usrtrack.h"
36 #include "efunction.h"
37 #include "edialogs.h"
38 #include "conlay.h"
39 #include "tecart.h"
40 #include "tecgen.h"
41 #include "tecschem.h"
42 #if SIMTOOL
43 # include "sim.h"
44 #endif
45
us_lambda(INTBIG count,CHAR * par[])46 void us_lambda(INTBIG count, CHAR *par[])
47 {
48 REGISTER CHAR *pp;
49 REGISTER INTBIG lam, oldlam, newunit, how;
50 REGISTER INTBIG l;
51 REGISTER WINDOWPART *w;
52 REGISTER NODEPROTO *np;
53 REGISTER LIBRARY *lib;
54 REGISTER TECHNOLOGY *tech;
55 TECHNOLOGY *techarray[1];
56 INTBIG newlam[1];
57 extern COMCOMP us_lambdachp, us_noyesp;
58
59 if (count > 0)
60 {
61 l = estrlen(pp = par[0]);
62
63 /* handle display unit setting */
64 if (namesamen(pp, x_("display-units"), l) == 0)
65 {
66 if (count >= 2)
67 {
68 l = estrlen(pp = par[1]);
69 if (namesamen(pp, x_("lambda"), l) == 0) newunit = DISPUNITLAMBDA; else
70 if (namesamen(pp, x_("inch"), l) == 0) newunit = DISPUNITINCH; else
71 if (namesamen(pp, x_("centimeter"), l) == 0 && l >= 7) newunit = DISPUNITCM; else
72 if (namesamen(pp, x_("millimeter"), l) == 0 && l >= 4) newunit = DISPUNITMM; else
73 if (namesamen(pp, x_("mil"), l) == 0 && l >= 3) newunit = DISPUNITMIL; else
74 if (namesamen(pp, x_("micron"), l) == 0 && l >= 3) newunit = DISPUNITMIC; else
75 if (namesamen(pp, x_("centimicron"), l) == 0 && l >= 7) newunit = DISPUNITCMIC; else
76 if (namesamen(pp, x_("nanometer"), l) == 0) newunit = DISPUNITNM; else
77 {
78 us_abortcommand(_("Unknown display unit: %s"), pp);
79 return;
80 }
81 setvalkey((INTBIG)us_tool, VTOOL, us_displayunitskey, newunit, VINTEGER);
82 }
83 switch (el_units&DISPLAYUNITS)
84 {
85 case DISPUNITLAMBDA:
86 ttyputverbose(M_("Distance expressed in lambda (currently %ld %ss)"),
87 el_curlib->lambda[el_curtech->techindex], unitsname(el_units));
88 break;
89 case DISPUNITINCH:
90 ttyputverbose(M_("Distance expressed in inches"));
91 break;
92 case DISPUNITCM:
93 ttyputverbose(M_("Distance expressed in centimeters"));
94 break;
95 case DISPUNITMM:
96 ttyputverbose(M_("Distance expressed in millimeters"));
97 break;
98 case DISPUNITMIL:
99 ttyputverbose(M_("Distance expressed in mils"));
100 break;
101 case DISPUNITMIC:
102 ttyputverbose(M_("Distance expressed in microns"));
103 break;
104 case DISPUNITCMIC:
105 ttyputverbose(M_("Distance expressed in centimicrons"));
106 break;
107 case DISPUNITNM:
108 ttyputverbose(M_("Distance expressed in nanometers"));
109 break;
110 }
111 return;
112 }
113
114 /* handle internal unit setting */
115 if (namesamen(pp, x_("internal-units"), l) == 0)
116 {
117 if (count >= 2)
118 {
119 l = estrlen(pp = par[1]);
120 if (namesamen(pp, x_("half-decimicron"), l) == 0 && l >= 6)
121 {
122 changeinternalunits(NOLIBRARY, el_units, INTUNITHDMIC);
123 } else if (namesamen(pp, x_("half-nanometer"), l) == 0 && l >= 6)
124 {
125 changeinternalunits(NOLIBRARY, el_units, INTUNITHNM);
126 } else
127 {
128 us_abortcommand(_("Unknown internal unit: %s"), pp);
129 return;
130 }
131 }
132 ttyputverbose(M_("Smallest internal unit is %s"), unitsname(el_units));
133 return;
134 }
135
136 if (namesamen(pp, x_("change-tech"), l) == 0 && l >= 8) how = 0; else
137 if (namesamen(pp, x_("change-lib"), l) == 0 && l >= 8) how = 1; else
138 if (namesamen(pp, x_("change-all-libs"), l) == 0 && l >= 8) how = 2; else
139 {
140 ttyputusage(x_("lambda change-tech|change-lib|change-all-libs VALUE"));
141 return;
142 }
143
144 if (count <= 1)
145 {
146 count = ttygetparam(M_("Lambda value: "), &us_lambdachp, MAXPARS-1, &par[1]) + 1;
147 if (count == 1)
148 {
149 us_abortedmsg();
150 return;
151 }
152 }
153
154 lam = eatoi(par[1]);
155 if (lam <= 0)
156 {
157 us_abortcommand(_("Lambda value must be positive"));
158 return;
159 }
160 if (lam / 4 * 4 != lam)
161 {
162 count = ttygetparam(_("Instability may result if lambda is not divisible by four. Continue? [n]"),
163 &us_noyesp, MAXPARS, par);
164 if (count <= 0 || namesamen(par[0], x_("yes"), estrlen(par[0])) != 0)
165 {
166 ttyputverbose(M_("No change made"));
167 return;
168 }
169 }
170
171 /* save highlighting */
172 us_pushhighlight();
173 us_clearhighlightcount();
174
175 oldlam = el_curlib->lambda[el_curtech->techindex];
176 techarray[0] = el_curtech;
177 newlam[0] = lam;
178 changelambda(1, techarray, newlam, el_curlib, how);
179 us_setlambda(NOWINDOWFRAME);
180 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
181 {
182 if (w->curnodeproto == NONODEPROTO) continue;
183 if (w->curnodeproto->tech != el_curtech) continue;
184 if (how == 2 || (how == 1 && w->curnodeproto->lib == el_curlib))
185 {
186 w->screenlx = muldiv(w->screenlx, lam, oldlam);
187 w->screenhx = muldiv(w->screenhx, lam, oldlam);
188 w->screenly = muldiv(w->screenly, lam, oldlam);
189 w->screenhy = muldiv(w->screenhy, lam, oldlam);
190 computewindowscale(w);
191 } else us_redisplay(w);
192 }
193
194 /* restore highlighting */
195 us_pophighlight(FALSE);
196 }
197
198 /* determine which technologies to report */
199 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology) tech->temp1 = 0;
200 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
201 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
202 np->tech->temp1++;
203 el_curtech->temp1++;
204 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
205 {
206 if (tech->temp1 == 0) continue;
207 ttyputverbose(M_("Lambda size for %s is %s"), tech->techname,
208 latoa(el_curlib->lambda[tech->techindex], 0));
209 }
210 }
211
us_library(INTBIG count,CHAR * par[])212 void us_library(INTBIG count, CHAR *par[])
213 {
214 REGISTER LIBRARY *lib, *olib, *lastlib, *mergelib, *oldlib;
215 REGISTER INTBIG i, l, makecurrent, multifile, found, total, stripopts,
216 retval, arg, newstate;
217 REGISTER CHAR *pp, *pt, *style, *libf, *oldlibfile, save;
218 REGISTER NODEPROTO *np;
219 REGISTER NODEINST *ni;
220 REGISTER BOOLEAN first, doquiet;
221 REGISTER VARIABLE *var;
222 REGISTER EDITOR *ed;
223 REGISTER WINDOWPART *w, *curw;
224 INTBIG lx, hx, ly, hy;
225 INTBIG dummy;
226 CHAR *newpar[5], *libn, *extn;
227 extern COMCOMP us_libraryp, us_yesnop;
228 REGISTER void *infstr;
229
230 if (count == 0)
231 {
232 count = ttygetparam(M_("Library option: "), &us_libraryp, MAXPARS, par);
233 if (count == 0)
234 {
235 us_abortedmsg();
236 return;
237 }
238 }
239 l = estrlen(pp = par[0]);
240
241 if (namesamen(pp, x_("default-path"), l) == 0 && l >= 9)
242 {
243 if (count < 2)
244 {
245 ttyputusage(x_("library default-path PATHNAME"));
246 return;
247 }
248 setlibdir(par[1]);
249 ttyputverbose(M_("Default library path is now '%s'"), el_libdir);
250 return;
251 }
252
253 if (namesamen(pp, x_("touch"), l) == 0 && l >= 1)
254 {
255 /* mark all libraries as "changed" */
256 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
257 {
258 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
259 lib->userbits |= LIBCHANGEDMAJOR | LIBCHANGEDMINOR;
260 }
261 ttyputmsg(_("All libraries now need to be saved"));
262 return;
263 }
264
265 if (namesamen(pp, x_("purge"), l) == 0 && l >= 1)
266 {
267 /* delete all cells that are not the most recent and are unused */
268 found = 1;
269 total = 0;
270 while (found != 0)
271 {
272 found = 0;
273 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
274 {
275 if (np->newestversion == np) continue;
276 if (np->firstinst != NONODEINST) continue;
277 ttyputmsg(_("Deleting cell %s"), describenodeproto(np));
278 us_dokillcell(np);
279 found++;
280 total++;
281 break;
282 }
283 }
284 if (total == 0) ttyputmsg(_("No unused old cell versions to delete")); else
285 ttyputmsg(_("Deleted %ld cells"), total);
286 return;
287 }
288
289 if (namesamen(pp, x_("kill"), l) == 0 && l >= 1)
290 {
291 if (count <= 1) lib = el_curlib; else
292 {
293 lib = getlibrary(par[1]);
294 if (lib == NOLIBRARY)
295 {
296 us_abortcommand(_("No library called %s"), par[1]);
297 return;
298 }
299 }
300
301 /* make sure that this isn't the last library */
302 i = 0;
303 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
304 {
305 if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
306 if (olib == lib) continue;
307 i++;
308 }
309 if (i == 0)
310 {
311 us_abortcommand(_("Cannot kill last library"));
312 return;
313 }
314
315 /* check for usage by other libraries */
316 first = TRUE;
317 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
318 olib->temp1 = 0;
319 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
320 {
321 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
322 ni->parent->lib->temp1 = 1;
323 }
324 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
325 {
326 if (olib == lib) continue;
327 if (olib->temp1 == 0) continue;
328 if (first)
329 {
330 first = FALSE;
331 ttyputerr(_("Cannot delete library %s because:"), lib->libname);
332 }
333 infstr = initinfstr();
334 formatinfstr(infstr, _(" These cells (in library %s) use it:"),
335 olib->libname);
336 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
337 {
338 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
339 {
340 if (ni->proto->primindex != 0) continue;
341 if (ni->proto->lib == lib) break;
342 }
343 if (ni == NONODEINST) continue;
344 formatinfstr(infstr, x_(" %s"), nldescribenodeproto(np));
345 }
346 ttyputmsg(x_("%s"), returninfstr(infstr));
347 }
348 if (!first) return;
349
350 /* make sure it hasn't changed (unless "safe" option is given) */
351 if (count <= 2 || namesamen(par[2], x_("safe"), estrlen(par[2])) != 0)
352 {
353 if (us_preventloss(lib, 1, TRUE)) return;
354 }
355
356 /* switch to another library if killing current one */
357 if (lib == el_curlib)
358 {
359 us_switchtolibrary(el_curlib->nextlibrary);
360 ttyputverbose(M_("Current library is now %s"), el_curlib->libname);
361 } else ttyputverbose(M_("Library %s killed"), lib->libname);
362
363 /* remove display of all cells in this library */
364 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
365 {
366 if (w->curnodeproto == NONODEPROTO) continue;
367 if (w->curnodeproto->lib == lib) us_clearwindow(w);
368 }
369
370 ttyputmsg(x_("Library %s closed"), lib->libname);
371
372 /* kill the library */
373 killlibrary(lib);
374
375 /*
376 * the cell structure has changed
377 *
378 * this wouldn't be necessary if the "killlibrary()" routine did a
379 * broadcast. Then it would be detected properly in "us_killobject"
380 */
381 us_redoexplorerwindow();
382 return;
383 }
384
385 if (namesamen(pp, x_("read"), l) == 0 && l >= 1)
386 {
387 if (count < 2)
388 {
389 ttyputusage(x_("library read FILENAME [options]"));
390 return;
391 }
392
393 /* get style of input */
394 libf = par[1];
395 makecurrent = 0;
396 style = x_("binary");
397 extn = x_(".elib");
398 mergelib = NOLIBRARY;
399 doquiet = FALSE;
400 while (count >= 3)
401 {
402 l = estrlen(pp = par[2]);
403 if (namesamen(pp, x_("binary"), l) == 0 && l >= 1) { style = x_("binary"); extn = x_(".elib"); doquiet = TRUE; } else
404 if (namesamen(pp, x_("cif"), l) == 0 && l >= 1) { style = x_("cif"); extn = x_(".cif"); doquiet = TRUE; } else
405 if (namesamen(pp, x_("def"), l) == 0 && l >= 1) { style = x_("def"); extn = x_(".def"); } else
406 if (namesamen(pp, x_("dxf"), l) == 0 && l >= 1) { style = x_("dxf"); extn = x_(".dxf"); } else
407 if (namesamen(pp, x_("edif"), l) == 0 && l >= 1) { style = x_("edif"); extn = x_(".edif"); } else
408 if (namesamen(pp, x_("gds"), l) == 0 && l >= 1) { style = x_("gds"); extn = x_(".gds"); doquiet = TRUE; } else
409 if (namesamen(pp, x_("lef"), l) == 0 && l >= 1) { style = x_("lef"); extn = x_(".lef"); } else
410 if (namesamen(pp, x_("sdf"), l) == 0 && l >= 2) { style = x_("sdf"); extn = x_(".sdf"); doquiet = TRUE; } else
411 if (namesamen(pp, x_("sue"), l) == 0 && l >= 2) { style = x_("sue"); extn = x_(".sue"); doquiet = TRUE; } else
412 if (namesamen(pp, x_("text"), l) == 0 && l >= 1) { style = x_("text"); extn = x_(".txt"); doquiet = TRUE; } else
413 if (namesamen(pp, x_("vhdl"), l) == 0 && l >= 1) { style = x_("vhdl"); extn = x_(".vhdl"); doquiet = TRUE; } else
414 if (namesamen(pp, x_("make-current"), l) == 0 && l >= 2) makecurrent++; else
415 if (namesamen(pp, x_("merge"), l) == 0 && l >= 2)
416 {
417 if (count < 4)
418 {
419 ttyputusage(x_("library read FILENAME merge LIBRARYNAME"));
420 return;
421 }
422 mergelib = getlibrary(par[3]);
423 if (mergelib == NOLIBRARY)
424 {
425 us_abortcommand(_("Cannot find merge library %s"), par[3]);
426 return;
427 }
428 count--;
429 par++;
430 } else
431 {
432 us_abortcommand(_("Read options: binary|cif|def|dxf|edif|gds|lef|sdf|sue|text|vhdl|make-current|(merge LIB)"));
433 return;
434 }
435 count--;
436 par++;
437 }
438
439 /* turn off highlighting */
440 us_clearhighlightcount();
441
442 /* see if multiple files were selected */
443 multifile = 0;
444 for(pt = libf; *pt != 0; pt++) if (*pt == NONFILECH) multifile++;
445
446 /* loop through all files */
447 retval = 0;
448 for(i=0; ; i++)
449 {
450 /* get the next file into "libf" */
451 for(pt = libf; *pt != 0 && *pt != NONFILECH; pt++) ;
452 save = *pt;
453 *pt = 0;
454
455 /* get file name and remove extension from library name */
456 (void)allocstring(&libn, skippath(libf), el_tempcluster);
457 l = estrlen(libn) - estrlen(extn);
458 if (namesame(&libn[l], extn) == 0)
459 {
460 libn[l] = 0;
461
462 /* remove extension from library file if not binary */
463 if (estrcmp(extn, x_(".elib")) != 0) libf[estrlen(libf) - estrlen(extn)] = 0;
464 }
465
466 oldlib = NOLIBRARY;
467 if (multifile != 0)
468 {
469 /* place the new library file name onto the current library */
470 lib = el_curlib;
471 oldlibfile = lib->libfile;
472 lib->libfile = libf;
473 } else if (mergelib != NOLIBRARY)
474 {
475 /* place the new library file name onto the merge library */
476 lib = mergelib;
477 oldlibfile = lib->libfile;
478 lib->libfile = libf;
479 } else
480 {
481 /* reading a new library (or replacing an old one) */
482 oldlib = getlibrary(libn);
483 if (oldlib != NOLIBRARY)
484 {
485 /* not a new library: make sure the old library is saved */
486 if (us_preventloss(oldlib, 2, TRUE) != 0)
487 {
488 efree(libn);
489 return;
490 }
491
492 /* replacing library: clear windows */
493 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
494 {
495 if (w->curnodeproto != NONODEPROTO &&
496 w->curnodeproto->lib == oldlib)
497 {
498 w->curnodeproto = NONODEPROTO;
499 us_redisplaynow(w, TRUE);
500 }
501 }
502
503 /* rename this library, delete it later */
504 oldlib->libname[0] = 0;
505 }
506
507 /* create the library */
508 lib = newlibrary(libn, libf);
509 if (lib == NOLIBRARY)
510 {
511 us_abortcommand(_("Cannot create library %s"), libn);
512 efree(libn);
513 return;
514 }
515 }
516
517 /* read the library */
518 if (multifile == 0) arg = 0; else
519 {
520 arg = 2;
521 if (i == 0) arg = 1; else
522 if (i == multifile) arg = 3;
523 }
524 if (mergelib == NOLIBRARY && doquiet) changesquiet(TRUE);
525 if (asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)style, arg) != 0)
526 retval = 1;
527 if (mergelib == NOLIBRARY && doquiet) changesquiet(FALSE);
528 if (multifile != 0 || mergelib != NOLIBRARY) lib->libfile = oldlibfile;
529
530 /* delete the former library if this replaced it */
531 if (oldlib != NOLIBRARY)
532 {
533 us_replacelibraryreferences(oldlib, lib);
534 if (oldlib == el_curlib) selectlibrary(lib, TRUE);
535 killlibrary(oldlib);
536 }
537
538 /* advance to the next file in the list */
539 *pt = (CHAR)save;
540 if (save == 0) break;
541 libf = pt + 1;
542 if (retval != 0) break;
543 }
544
545 if (retval == 0)
546 {
547 if (makecurrent != 0 || lib == el_curlib)
548 {
549 #if SIMTOOL
550 sim_window_stopsimulation();
551 #endif
552
553 selectlibrary(lib, TRUE);
554 us_setlambda(NOWINDOWFRAME);
555 if (us_curnodeproto == NONODEPROTO || us_curnodeproto->primindex == 0)
556 {
557 nextchangequiet();
558 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_node_key,
559 (INTBIG)el_curtech->firstnodeproto, VNODEPROTO|VDONTSAVE);
560 us_shadownodeproto(NOWINDOWFRAME, el_curtech->firstnodeproto);
561 }
562 np = el_curlib->curnodeproto;
563 if (el_curwindowpart != NOWINDOWPART &&
564 el_curwindowpart->curnodeproto == NONODEPROTO &&
565 (el_curwindowpart->state&WINDOWTYPE) != EXPLORERWINDOW)
566 curw = el_curwindowpart; else
567 {
568 for(curw = el_topwindowpart; curw != NOWINDOWPART; curw = curw->nextwindowpart)
569 if (curw->curnodeproto == NONODEPROTO &&
570 (curw->state&WINDOWTYPE) != EXPLORERWINDOW) break;
571 }
572 if (np != NONODEPROTO)
573 {
574 if (curw == NOWINDOWPART)
575 {
576 curw = us_wantnewwindow(0);
577 if (curw == NOWINDOWPART)
578 {
579 us_abortcommand(_("Cannot create new window"));
580 return;
581 }
582 } else
583 {
584 if (curw->termhandler != 0)
585 (*curw->termhandler)(curw);
586 if ((curw->state&WINDOWTYPE) == POPTEXTWINDOW)
587 screenrestorebox(curw->editor->savedbox, -1);
588 if ((curw->state&WINDOWTYPE) == TEXTWINDOW ||
589 (curw->state&WINDOWTYPE) == POPTEXTWINDOW)
590 us_freeeditor(curw->editor);
591 }
592 if ((np->cellview->viewstate&TEXTVIEW) != 0)
593 {
594 /* text window: make an editor */
595 if (us_makeeditor(curw, describenodeproto(np), &dummy, &dummy) == NOWINDOWPART)
596 {
597 efree(libn);
598 return;
599 }
600
601 /* get the text that belongs here */
602 var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
603 if (var == NOVARIABLE)
604 {
605 newpar[0] = x_("");
606 var = setvalkey((INTBIG)np, VNODEPROTO, el_cell_message_key,
607 (INTBIG)newpar, VSTRING|VISARRAY|(1<<VLENGTHSH));
608 if (var == NOVARIABLE)
609 {
610 efree(libn);
611 return;
612 }
613 }
614
615 /* setup for editing */
616 curw->curnodeproto = np;
617 ed = curw->editor;
618 ed->editobjaddr = (CHAR *)np;
619 ed->editobjtype = VNODEPROTO;
620 ed->editobjqual = x_("FACET_message");
621 ed->editobjvar = var;
622
623 /* load the text into the window */
624 us_suspendgraphics(curw);
625 l = getlength(var);
626 for(i=0; i<l; i++)
627 {
628 pp = ((CHAR **)var->addr)[i];
629 if (i == l-1 && *pp == 0) continue;
630 us_addline(curw, i, pp);
631 }
632 us_resumegraphics(curw);
633 curw->changehandler = us_textcellchanges;
634 us_setcellname(curw);
635 } else
636 {
637 /* adjust the new window to account for borders in the old one */
638 if ((curw->state&WINDOWTYPE) != DISPWINDOW)
639 {
640 curw->usehx -= DISPLAYSLIDERSIZE;
641 curw->usely += DISPLAYSLIDERSIZE;
642 }
643 if ((curw->state&WINDOWTYPE) == WAVEFORMWINDOW)
644 {
645 curw->uselx -= DISPLAYSLIDERSIZE;
646 curw->usely -= DISPLAYSLIDERSIZE;
647 }
648 if ((curw->state&WINDOWMODE) != 0)
649 {
650 curw->uselx -= WINDOWMODEBORDERSIZE;
651 curw->usehx += WINDOWMODEBORDERSIZE;
652 curw->usely -= WINDOWMODEBORDERSIZE;
653 curw->usehy += WINDOWMODEBORDERSIZE;
654 }
655 curw->curnodeproto = np;
656 newstate = (curw->state & ~(WINDOWTYPE|WINDOWMODE)) | DISPWINDOW;
657 if ((np->userbits&TECEDITCELL) != 0) newstate |= WINDOWTECEDMODE;
658 us_setwindowmode(curw, curw->state, newstate);
659 curw->editor = NOEDITOR;
660 curw->buttonhandler = DEFAULTBUTTONHANDLER;
661 curw->charhandler = DEFAULTCHARHANDLER;
662 curw->changehandler = DEFAULTCHANGEHANDLER;
663 curw->termhandler = DEFAULTTERMHANDLER;
664 curw->redisphandler = DEFAULTREDISPHANDLER;
665 us_fullview(np, &lx, &hx, &ly, &hy);
666 us_squarescreen(curw, NOWINDOWPART, FALSE, &lx, &hx, &ly, &hy, 0);
667 curw->screenlx = lx;
668 curw->screenhx = hx;
669 curw->screenly = ly;
670 curw->screenhy = hy;
671 computewindowscale(curw);
672 us_setcellname(curw);
673 us_setcellsize(curw);
674 us_setgridsize(curw);
675 if (curw->redisphandler != 0)
676 (*curw->redisphandler)(curw);
677 us_state |= CURCELLCHANGED;
678 }
679 }
680
681 /* redisplay the explorer window */
682 us_redoexplorerwindow();
683 }
684 } else if (mergelib == NOLIBRARY)
685 {
686 /* library is incomplete: remove it from the list */
687 if (el_curlib != lib)
688 {
689 /* this is not the current library: safe to delete */
690 lastlib = NOLIBRARY;
691 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
692 {
693 if (olib == lib) break;
694 lastlib = olib;
695 }
696 if (lastlib != NOLIBRARY) lastlib->nextlibrary = lib->nextlibrary;
697 } else
698 {
699 /* current library is incomplete */
700 if (el_curlib->nextlibrary == NOLIBRARY)
701 {
702 /* must create a new library: it is the only one */
703 el_curlib = alloclibrary();
704 (void)allocstring(&el_curlib->libname, lib->libname, el_curlib->cluster);
705 (void)allocstring(&el_curlib->libfile, lib->libfile, el_curlib->cluster);
706 el_curlib->nextlibrary = NOLIBRARY;
707 } else el_curlib = el_curlib->nextlibrary;
708
709 us_clearhighlightcount();
710 us_setlambda(NOWINDOWFRAME);
711 if (us_curnodeproto == NONODEPROTO || us_curnodeproto->primindex == 0)
712 {
713 if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(NONODEPROTO); else
714 us_setnodeproto(el_curtech->firstnodeproto);
715 }
716 if (el_curlib->curnodeproto != NONODEPROTO)
717 {
718 newpar[0] = describenodeproto(el_curlib->curnodeproto);
719 us_editcell(1, newpar);
720 }
721 }
722 }
723 us_endbatch();
724 efree(libn);
725 noundoallowed();
726 return;
727 }
728
729 if (namesamen(pp, x_("use"), l) == 0 && l >= 1)
730 {
731 if (count <= 1)
732 {
733 ttyputusage(x_("library use LIBNAME"));
734 return;
735 }
736
737 /* find actual library name */
738 libn = skippath(par[1]);
739
740 lib = getlibrary(libn);
741 if (lib != NOLIBRARY)
742 {
743 if (el_curlib == lib) return;
744 us_switchtolibrary(lib);
745 return;
746 }
747
748 /* create new library */
749 lib = newlibrary(libn, par[1]);
750 if (lib == NOLIBRARY)
751 {
752 us_abortcommand(_("Cannot create library %s"), libn);
753 return;
754 }
755
756 /* make this library the current one */
757 us_switchtolibrary(lib);
758 ttyputverbose(M_("New library: %s"), libn);
759 return;
760 }
761
762 if (namesamen(pp, x_("new"), l) == 0 && l >= 1)
763 {
764 if (count <= 1)
765 {
766 ttyputusage(x_("library new LIBNAME"));
767 return;
768 }
769
770 /* find actual library name */
771 libn = skippath(par[1]);
772
773 lib = getlibrary(libn);
774 if (lib != NOLIBRARY)
775 {
776 us_abortcommand(_("Already a library called '%s'"), libn);
777 return;
778 }
779
780 /* create new library */
781 lib = newlibrary(libn, par[1]);
782 if (lib == NOLIBRARY)
783 {
784 us_abortcommand(_("Cannot create library %s"), libn);
785 return;
786 }
787
788 ttyputverbose(M_("New library: %s"), libn);
789 return;
790 }
791
792 if (namesamen(pp, x_("save"), l) == 0 && l >= 2)
793 {
794 if (us_saveeverything())
795 {
796 /* manage reset of session log (if all information is saved) */
797 us_continuesessionlogging();
798 }
799 return;
800 }
801
802 if (namesamen(pp, x_("write"), l) == 0 && l >= 1)
803 {
804 if (count < 2)
805 {
806 ttyputusage(x_("library write LIBNAME [options]"));
807 return;
808 }
809
810 /* get style of output */
811 style = x_("binary");
812 if (count >= 3)
813 {
814 l = estrlen(pp = par[2]);
815 if (l >= 1 && namesamen(pp, x_("binary"), l) == 0) style = x_("binary"); else
816 if (l >= 1 && namesamen(pp, x_("cif"), l) == 0) style = x_("cif"); else
817 if (l >= 1 && namesamen(pp, x_("dxf"), l) == 0) style = x_("dxf"); else
818 if (l >= 2 && namesamen(pp, x_("eagle"), l) == 0) style = x_("eagle"); else
819 if (l >= 2 && namesamen(pp, x_("ecad"), l) == 0) style = x_("ecad"); else
820 if (l >= 2 && namesamen(pp, x_("edif"), l) == 0) style = x_("edif"); else
821 if (l >= 1 && namesamen(pp, x_("gds"), l) == 0) style = x_("gds"); else
822 if (l >= 1 && namesamen(pp, x_("hpgl"), l) == 0) style = x_("hpgl"); else
823 if (l >= 2 && namesamen(pp, x_("lef"), l) == 0) style = x_("lef"); else
824 if (l >= 1 && namesamen(pp, x_("l"), l) == 0) style = x_("l"); else
825 if (l >= 2 && namesamen(pp, x_("pads"), l) == 0) style = x_("pads"); else
826 if (l >= 2 && namesamen(pp, x_("postscript"), l) == 0) style = x_("postscript"); else
827 if (l >= 2 && namesamen(pp, x_("printed-postscript"), l) == 0) style = x_("printed-postscript"); else
828 if (l >= 1 && namesamen(pp, x_("quickdraw"), l) == 0) style = x_("quickdraw"); else
829 if (l >= 1 && namesamen(pp, x_("skill"), l) == 0) style = x_("skill"); else
830 if (l >= 1 && namesamen(pp, x_("text"), l) == 0) style = x_("text"); else
831 {
832 us_abortcommand(_("File formats: binary|cif|dxf|eagle|ecad|edif|gds|hpgl|l|lef|pads|postscript|printed-postscript|quickdraw|skill|text"));
833 return;
834 }
835 }
836
837 /* get library to write */
838 lib = getlibrary(par[1]);
839 if (lib == NOLIBRARY)
840 {
841 us_abortcommand(_("No library called %s"), par[1]);
842 return;
843 }
844
845 /* do it */
846 if (namesame(style, x_("binary")) == 0 || namesame(style, x_("text")) == 0) stripopts = 1; else
847 stripopts = 0;
848 if (stripopts != 0) makeoptionstemporary(lib);
849 retval = asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)style);
850 if (stripopts != 0) restoreoptionstate(lib);
851 if (retval != 0) return;
852
853 /* offer to save any referenced libraries */
854 if (namesame(style, x_("binary")) == 0)
855 {
856 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
857 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
858 np->temp2 = 0;
859 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
860 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
861 if (ni->proto->primindex == 0)
862 ni->proto->temp2 = 1;
863 for(olib = el_curlib; olib != NOLIBRARY; olib = olib->nextlibrary)
864 {
865 if (olib == lib) continue;
866 for(np = olib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
867 if (np->temp2 != 0) break;
868 if (np == NONODEPROTO) continue;
869 if ((olib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) == 0) continue;
870
871 infstr = initinfstr();
872 if ((olib->userbits&LIBCHANGEDMAJOR) == 0)
873 {
874 formatinfstr(infstr, _("Also save referenced library %s (which has changed insignificantly)?"),
875 olib->libname);
876 } else
877 {
878 formatinfstr(infstr, _("Also save referenced library %s (which has changed significantly)?"),
879 olib->libname);
880 }
881 i = ttygetparam(returninfstr(infstr), &us_yesnop, 3, newpar);
882 if (i == 1 && newpar[0][0] == 'n') continue;
883 makeoptionstemporary(olib);
884 (void)asktool(io_tool, x_("write"), (INTBIG)olib, (INTBIG)style);
885 restoreoptionstate(olib);
886 }
887 }
888
889 /* rewind session recording if writing in permanent format */
890 if (*style == 'b' || *style == 't')
891 {
892 /* manage reset of session log (if all information is saved) */
893 us_continuesessionlogging();
894 }
895 return;
896 }
897
898 ttyputbadusage(x_("library"));
899 }
900
us_macbegin(INTBIG count,CHAR * par[])901 void us_macbegin(INTBIG count, CHAR *par[])
902 {
903 REGISTER INTBIG i, l;
904 REGISTER BOOLEAN verbose, execute;
905 REGISTER INTBIG key;
906 REGISTER CHAR *ch, *pp;
907 CHAR *newmacro[3];
908 extern COMCOMP us_macbeginnp;
909 REGISTER VARIABLE *var;
910 REGISTER void *infstr;
911
912 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
913 if (var != NOVARIABLE)
914 {
915 us_abortcommand(_("Already defining a macro"));
916 return;
917 }
918
919 /* get macro name */
920 if (count == 0)
921 {
922 count = ttygetparam(M_("Macro name: "), &us_macbeginnp, MAXPARS, par);
923 if (count == 0)
924 {
925 us_abortedmsg();
926 return;
927 }
928 }
929 pp = par[0];
930
931 /* get switches */
932 verbose = FALSE; execute = TRUE;
933 for(i=1; i<count; i++)
934 {
935 ch = par[i];
936 l = estrlen(ch);
937 if (namesamen(ch, x_("verbose"), l) == 0) verbose = TRUE; else
938 if (namesamen(ch, x_("no-execute"), l) == 0) execute = FALSE; else
939 {
940 ttyputusage(x_("macbegin MACRONAME [verbose|no-execute]"));
941 return;
942 }
943 }
944
945 /* make sure macro name isn't overloading existing command */
946 for(i=0; us_lcommand[i].name != 0; i++)
947 if (namesame(pp, us_lcommand[i].name) == 0)
948 {
949 us_abortcommand(_("There is a command with that name"));
950 return;
951 }
952
953 /* see if macro name already exists */
954 if (us_getmacro(pp) == NOVARIABLE)
955 {
956 /* new macro name, check for validity */
957 for(ch = pp; *ch != 0; ch++) if (*ch == ' ' || *ch == '\t')
958 {
959 us_abortcommand(_("Macro name must not have embedded spaces"));
960 return;
961 }
962 }
963
964 /* create the macro variable */
965 infstr = initinfstr();
966 addstringtoinfstr(infstr, x_("USER_macro_"));
967 addstringtoinfstr(infstr, pp);
968 key = makekey(returninfstr(infstr));
969
970 /* build the first two lines of the macro */
971 infstr = initinfstr();
972 if (us_curmacropack != NOMACROPACK)
973 {
974 addstringtoinfstr(infstr, x_("macropack="));
975 addstringtoinfstr(infstr, us_curmacropack->packname);
976 }
977 if (verbose) addstringtoinfstr(infstr, x_(" verbose"));
978 if (!execute) addstringtoinfstr(infstr, x_(" noexecute"));
979 newmacro[0] = returninfstr(infstr);
980 newmacro[1] = x_(""); /* no parameters yet */
981 newmacro[2] = x_(""); /* no parsing structures yet */
982 (void)setvalkey((INTBIG)us_tool, VTOOL, key, (INTBIG)newmacro,
983 VSTRING|VISARRAY|(3<<VLENGTHSH)|VDONTSAVE);
984
985 /* turn on macro remembering */
986 nextchangequiet();
987 (void)setvalkey((INTBIG)us_tool, VTOOL, us_macrobuildingkey, (INTBIG)pp, VSTRING|VDONTSAVE);
988 nextchangequiet();
989 (void)setvalkey((INTBIG)us_tool, VTOOL, us_macrorunningkey, (INTBIG)pp, VSTRING|VDONTSAVE);
990
991 ttyputmsg(_("Remembering %s..."), pp);
992 }
993
us_macdone(INTBIG count,CHAR * par[])994 void us_macdone(INTBIG count, CHAR *par[])
995 {
996 REGISTER VARIABLE *var;
997
998 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrorunningkey);
999 if (var == NOVARIABLE)
1000 {
1001 us_abortcommand(_("Can only stop execution of a macro if one is running"));
1002 return;
1003 }
1004 us_state |= MACROTERMINATED;
1005 }
1006
us_macend(INTBIG count,CHAR * par[])1007 void us_macend(INTBIG count, CHAR *par[])
1008 {
1009 REGISTER VARIABLE *var;
1010
1011 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrobuildingkey);
1012 if (var == NOVARIABLE)
1013 {
1014 us_abortcommand(_("Not in a macro"));
1015 return;
1016 }
1017 ttyputmsg(_("%s defined"), (CHAR *)var->addr);
1018 nextchangequiet();
1019 (void)delvalkey((INTBIG)us_tool, VTOOL, us_macrobuildingkey);
1020 if (getvalkey((INTBIG)us_tool, VTOOL, VSTRING, us_macrorunningkey) != NOVARIABLE)
1021 {
1022 nextchangequiet();
1023 (void)delvalkey((INTBIG)us_tool, VTOOL, us_macrorunningkey);
1024 }
1025 }
1026
us_menu(INTBIG count,CHAR * par[])1027 void us_menu(INTBIG count, CHAR *par[])
1028 {
1029 REGISTER INTBIG l, s, i, total, changed, position, x, y, varkey,
1030 j, len, arctot, pintot, comptot, puretot, fun, coms;
1031 REGISTER BOOLEAN autoset, verbose;
1032 BOOLEAN butstate;
1033 REGISTER CHAR *pp, **temp;
1034 CHAR number[10], *pt, *implicit[6];
1035 POPUPMENU *pm, *cpm, *newpm;
1036 REGISTER POPUPMENUITEM *mi, *miret;
1037 NODEPROTO *np;
1038 ARCPROTO *ap;
1039 REGISTER USERCOM *uc;
1040 REGISTER VARIABLE *var;
1041 COMCOMP *comarray[MAXPARS];
1042 COMMANDBINDING commandbinding;
1043 extern COMCOMP us_menup;
1044 REGISTER void *infstr;
1045
1046 /* with no arguments, toggle the menu state */
1047 if (count == 0)
1048 {
1049 count = ttygetparam(_("Menu display option: "), &us_menup, MAXPARS, par);
1050 if (count == 0)
1051 {
1052 us_abortedmsg();
1053 return;
1054 }
1055 }
1056
1057 /* check for simple changes of the menu display */
1058 l = estrlen(pp = par[0]);
1059 if (namesamen(pp, x_("on"), l) == 0 && l >= 2)
1060 {
1061 if ((us_tool->toolstate&MENUON) != 0)
1062 {
1063 us_abortcommand(_("Menu is already displayed"));
1064 return;
1065 }
1066
1067 /* save highlighting */
1068 us_pushhighlight();
1069 us_clearhighlightcount();
1070
1071 startobjectchange((INTBIG)us_tool, VTOOL);
1072 (void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate|MENUON,
1073 VINTEGER);
1074 endobjectchange((INTBIG)us_tool, VTOOL);
1075
1076 /* restore highlighting */
1077 us_pophighlight(FALSE);
1078 return;
1079 }
1080
1081 if (namesamen(pp, x_("off"), l) == 0 && l >= 2)
1082 {
1083 if ((us_tool->toolstate&MENUON) == 0)
1084 {
1085 us_abortcommand(_("Menu is not displayed"));
1086 return;
1087 }
1088
1089 /* save highlighting */
1090 us_pushhighlight();
1091 us_clearhighlightcount();
1092
1093 startobjectchange((INTBIG)us_tool, VTOOL);
1094 (void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate & ~MENUON, VINTEGER);
1095 endobjectchange((INTBIG)us_tool, VTOOL);
1096
1097 /* restore highlighting */
1098 us_pophighlight(FALSE);
1099 return;
1100 }
1101
1102 if (namesamen(pp, x_("dopopup"), l) == 0 && l >= 1)
1103 {
1104 if (count <= 1)
1105 {
1106 implicit[0] = x_("telltool");
1107 implicit[1] = x_("user");
1108 uc = us_buildcommand(2, implicit);
1109 } else uc = us_buildcommand(count-1, &par[1]);
1110 if (uc == NOUSERCOM)
1111 {
1112 us_abortcommand(_("Command '%s' not found"), par[1]);
1113 return;
1114 }
1115
1116 /* loop through the popup menus of this command */
1117 for(;;)
1118 {
1119 /* convert to a string of command completion objects */
1120 total = us_fillcomcomp(uc, comarray);
1121 if (total <= uc->count) break;
1122
1123 /* count the number of options */
1124 us_pathiskey = comarray[uc->count]->ifmatch;
1125 pt = x_("");
1126 (void)(*comarray[uc->count]->toplist)(&pt);
1127 for(coms=0; (pp = (*comarray[uc->count]->nextcomcomp)()); coms++) ;
1128 if ((comarray[uc->count]->interpret&INCLUDENOISE) != 0) coms++;
1129
1130 /* build the prompt */
1131 infstr = initinfstr();
1132 addstringtoinfstr(infstr, comarray[uc->count]->noise);
1133
1134 /* if there are no choices, prompt directly */
1135 if (coms == 0)
1136 {
1137 addstringtoinfstr(infstr, x_(": "));
1138 pp = ttygetline(returninfstr(infstr));
1139 if (pp == 0) break;
1140 (void)allocstring(&uc->word[uc->count], pp, us_tool->cluster);
1141 uc->count++;
1142 continue;
1143 }
1144
1145 /* create the popup menu */
1146 pm = (POPUPMENU *)emalloc(sizeof(POPUPMENU), el_tempcluster);
1147 if (pm == 0) return;
1148 pm->name = x_("noname");
1149 (void)allocstring(&pm->header, returninfstr(infstr), el_tempcluster);
1150 pm->total = coms;
1151 mi = (POPUPMENUITEM *)emalloc((coms * (sizeof (POPUPMENUITEM))), el_tempcluster);
1152 if (mi == 0) return;
1153 pm->list = mi;
1154
1155 /* fill the popup menu */
1156 pt = x_("");
1157 (void)(*comarray[uc->count]->toplist)(&pt);
1158 for(i=0; i<coms; i++)
1159 {
1160 mi[i].valueparse = NOCOMCOMP;
1161 mi[i].response = NOUSERCOM;
1162
1163 /* if noise is includable, do it first */
1164 if (i == 0 && (comarray[uc->count]->interpret&INCLUDENOISE) != 0)
1165 {
1166 mi[i].attribute = comarray[uc->count]->noise;
1167 if (comarray[uc->count]->def != 0)
1168 {
1169 mi[i].maxlen = maxi(20, estrlen(comarray[uc->count]->def));
1170 mi[i].value = (CHAR *)emalloc((mi[i].maxlen+1) * SIZEOFCHAR, el_tempcluster);
1171 (void)estrcpy(mi[i].value, comarray[uc->count]->def);
1172 } else
1173 {
1174 mi[i].maxlen = 20;
1175 mi[i].value = (CHAR *)emalloc((mi[i].maxlen+1) * SIZEOFCHAR, el_tempcluster);
1176 (void)estrcpy(mi[i].value, x_("*"));
1177 }
1178 continue;
1179 }
1180
1181 /* normal entry */
1182 mi[i].attribute = (*comarray[uc->count]->nextcomcomp)();
1183 mi[i].value = 0;
1184 mi[i].maxlen = -1;
1185
1186 /* see what would come next with this keyword */
1187 (void)allocstring(&uc->word[uc->count], mi[i].attribute, el_tempcluster);
1188 uc->count++;
1189 total = us_fillcomcomp(uc, comarray);
1190 uc->count--;
1191 efree(uc->word[uc->count]);
1192 if (total > uc->count+1)
1193 {
1194 if ((comarray[uc->count+1]->interpret&INPUTOPT) != 0)
1195 {
1196 mi[i].valueparse = comarray[uc->count+1];
1197 if (comarray[uc->count+1]->def != 0)
1198 {
1199 mi[i].maxlen = maxi(20, estrlen(comarray[uc->count+1]->def));
1200 mi[i].value = (CHAR *)emalloc((mi[i].maxlen+1) * SIZEOFCHAR, el_tempcluster);
1201 (void)estrcpy(mi[i].value, comarray[uc->count+1]->def);
1202 } else
1203 {
1204 mi[i].maxlen = 20;
1205 mi[i].value = (CHAR *)emalloc((mi[i].maxlen+1) * SIZEOFCHAR, el_tempcluster);
1206 (void)estrcpy(mi[i].value, x_("*"));
1207 }
1208 }
1209 }
1210 }
1211
1212 /* invoke the popup menu */
1213 butstate = TRUE;
1214 cpm = pm;
1215 miret = us_popupmenu(&cpm, &butstate, TRUE, -1, -1, 0);
1216 if (miret == 0) us_abortcommand(_("Sorry, this display cannot support popup menus"));
1217 if (miret == NOPOPUPMENUITEM || miret == 0)
1218 {
1219 efree((CHAR *)mi);
1220 efree((CHAR *)pm->header);
1221 efree((CHAR *)pm);
1222 break;
1223 }
1224
1225 /* see if multiple answers were given */
1226 changed = 0;
1227 for(i=0; i<pm->total; i++) if (mi[i].changed) changed++;
1228 if (changed > 1 || (changed == 1 && miret->changed == 0))
1229 {
1230 if ((comarray[uc->count]->interpret&MULTIOPT) == 0)
1231 {
1232 us_abortcommand(_("Multiple commands cannot be selected"));
1233 return;
1234 }
1235
1236 /* tack on all of the answers */
1237 for(i=0; i<pm->total; i++) if (mi[i].changed)
1238 {
1239 if (uc->count >= MAXPARS-1) break;
1240 (void)allocstring(&uc->word[uc->count++], mi[i].attribute, us_tool->cluster);
1241 (void)allocstring(&uc->word[uc->count++], mi[i].value, us_tool->cluster);
1242 }
1243 if (!miret->changed && uc->count < MAXPARS)
1244 (void)allocstring(&uc->word[uc->count++], miret->attribute, us_tool->cluster);
1245
1246 for(i=0; i<pm->total; i++)
1247 if (mi[i].maxlen >= 0) efree(mi[i].value);
1248 efree((CHAR *)mi);
1249 efree((CHAR *)pm);
1250 break;
1251 }
1252
1253 /* if noise was mentioned, copy the value */
1254 if (miret == mi && miret->changed &&
1255 (comarray[uc->count]->interpret&INCLUDENOISE) != 0)
1256 {
1257 (void)allocstring(&uc->word[uc->count++], miret->value, us_tool->cluster);
1258 } else
1259 {
1260 (void)allocstring(&uc->word[uc->count++], miret->attribute, us_tool->cluster);
1261 if (miret->changed)
1262 (void)allocstring(&uc->word[uc->count++], miret->value, us_tool->cluster);
1263 }
1264 for(i=0; i<pm->total; i++)
1265 if (mi[i].maxlen >= 0) efree(mi[i].value);
1266 efree((CHAR *)mi);
1267 efree((CHAR *)pm);
1268 }
1269
1270 /* issue the completed command */
1271 if ((us_tool->toolstate&ECHOBIND) != 0) verbose = TRUE; else
1272 verbose = FALSE;
1273 us_execute(uc, verbose, FALSE, TRUE);
1274 us_freeusercom(uc);
1275 return;
1276 }
1277
1278 if (namesamen(pp, x_("popup"), l) == 0 && l >= 1)
1279 {
1280 if (count <= 2)
1281 {
1282 ttyputusage(x_("menu popup NAME OPTIONS"));
1283 return;
1284 }
1285
1286 /* check out the name of the pop-up menu */
1287 pm = us_getpopupmenu(par[1]);
1288
1289 /* determine what to do with the menu */
1290 l = estrlen(pp = par[2]);
1291 if (namesamen(pp, x_("header"), l) == 0 && l >= 1)
1292 {
1293 /* set header: ensure it is specified */
1294 if (count <= 3)
1295 {
1296 ttyputusage(x_("menu popup header MESSAGE"));
1297 return;
1298 }
1299 if (pm == NOPOPUPMENU)
1300 {
1301 us_abortcommand(_("No popup menu called %s"), par[1]);
1302 return;
1303 }
1304 infstr = initinfstr();
1305 addstringtoinfstr(infstr, x_("USER_binding_popup_"));
1306 addstringtoinfstr(infstr, par[1]);
1307 varkey = makekey(returninfstr(infstr));
1308 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, varkey);
1309 if (var == NOVARIABLE)
1310 {
1311 us_abortcommand(_("Cannot find the menu"));
1312 return;
1313 }
1314 (void)setindkey((INTBIG)us_tool, VTOOL, varkey, 0, (INTBIG)par[3]);
1315 return;
1316 }
1317 if (namesamen(pp, x_("size"), l) == 0 && l >= 1)
1318 {
1319 /* set size: ensure it is specified */
1320 if (count <= 3)
1321 {
1322 ttyputusage(x_("menu popup NAME size SIZE"));
1323 return;
1324 }
1325 s = myatoi(par[3]);
1326 if (s <= 0)
1327 {
1328 us_abortcommand(_("Popup menu size must be positive"));
1329 return;
1330 }
1331
1332 /* set size of menu */
1333 if (pm == NOPOPUPMENU)
1334 {
1335 /* create the variable with the popup menu */
1336 temp = (CHAR **)emalloc(((s+1) * (sizeof (CHAR *))), el_tempcluster);
1337 (void)allocstring(&temp[0], x_("MENU!"), el_tempcluster);
1338 for(i=0; i<s; i++)
1339 {
1340 infstr = initinfstr();
1341 addstringtoinfstr(infstr, x_("inputpopup="));
1342 addstringtoinfstr(infstr, par[1]);
1343 addstringtoinfstr(infstr, x_(" command=bind set popup "));
1344 addstringtoinfstr(infstr, par[1]);
1345 (void)esnprintf(number, 10, x_(" %ld"), i);
1346 addstringtoinfstr(infstr, number);
1347 (void)allocstring(&temp[i+1], returninfstr(infstr), el_tempcluster);
1348 }
1349 infstr = initinfstr();
1350 addstringtoinfstr(infstr, x_("USER_binding_popup_"));
1351 addstringtoinfstr(infstr, par[1]);
1352 varkey = makekey(returninfstr(infstr));
1353 (void)setvalkey((INTBIG)us_tool, VTOOL, varkey, (INTBIG)temp,
1354 VSTRING|VISARRAY|VDONTSAVE|((s+1)<<VLENGTHSH));
1355 for(i=0; i<=s; i++) efree(temp[i]);
1356 efree((CHAR *)temp);
1357 } else
1358 {
1359 /* get the former popup menu */
1360 infstr = initinfstr();
1361 addstringtoinfstr(infstr, x_("USER_binding_popup_"));
1362 addstringtoinfstr(infstr, par[1]);
1363 varkey = makekey(returninfstr(infstr));
1364 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, varkey);
1365 if (var == NOVARIABLE)
1366 {
1367 us_abortcommand(_("Cannot find popup menu %s"), par[1]);
1368 return;
1369 }
1370 len = getlength(var);
1371
1372 /* create the new popup menu */
1373 temp = (CHAR **)emalloc(((s+1) * (sizeof (CHAR *))), el_tempcluster);
1374 if (temp == 0) return;
1375 (void)allocstring(&temp[0], ((CHAR **)var->addr)[0], el_tempcluster);
1376
1377 /* copy the existing menu entries */
1378 for(i=1; i<mini((s+1), len); i++)
1379 {
1380 us_parsebinding(((CHAR **)var->addr)[i], &commandbinding);
1381 infstr = initinfstr();
1382 if (commandbinding.inputpopup) addstringtoinfstr(infstr, x_("input"));
1383 addstringtoinfstr(infstr, x_("popup="));
1384 addstringtoinfstr(infstr, par[1]);
1385 if (commandbinding.menumessage != 0)
1386 {
1387 addstringtoinfstr(infstr, x_(" message=\""));
1388 addstringtoinfstr(infstr, commandbinding.menumessage);
1389 addtoinfstr(infstr, '"');
1390 }
1391 addstringtoinfstr(infstr, x_(" command="));
1392 addstringtoinfstr(infstr, commandbinding.command);
1393 (void)allocstring(&temp[i], returninfstr(infstr), el_tempcluster);
1394 us_freebindingparse(&commandbinding);
1395 }
1396
1397 for(j=i; j<s+1; j++)
1398 {
1399 infstr = initinfstr();
1400 addstringtoinfstr(infstr, x_("inputpopup="));
1401 addstringtoinfstr(infstr, par[1]);
1402 addstringtoinfstr(infstr, x_(" command=bind set popup "));
1403 addstringtoinfstr(infstr, par[1]);
1404 (void)esnprintf(number, 10, x_(" %ld"), j);
1405 addstringtoinfstr(infstr, number);
1406 (void)allocstring(&temp[j], returninfstr(infstr), el_tempcluster);
1407 }
1408 (void)setvalkey((INTBIG)us_tool, VTOOL, varkey, (INTBIG)temp,
1409 VSTRING|VISARRAY|VDONTSAVE|((s+1)<<VLENGTHSH));
1410 for(i=0; i<=s; i++) efree(temp[i]);
1411 efree((CHAR *)temp);
1412 newpm = us_getpopupmenu(par[1]);
1413 for(i=0; i<us_pulldownmenucount; i++)
1414 us_recursivelyreplacemenu(us_pulldowns[i], pm, newpm);
1415 }
1416 return;
1417 }
1418 ttyputbadusage(x_("menu popup"));
1419 return;
1420 }
1421
1422 if (namesamen(pp, x_("setmenubar"), l) == 0 && l >= 2)
1423 {
1424 /* free former menubar information */
1425 if (us_pulldownmenucount != 0)
1426 {
1427 efree((CHAR *)us_pulldowns);
1428 efree((CHAR *)us_pulldownmenupos);
1429 }
1430 us_pulldownmenucount = 0;
1431
1432 /* allocate new menubar information */
1433 if (count > 1)
1434 {
1435 us_pulldowns = (POPUPMENU **)emalloc((count-1) * (sizeof (POPUPMENU *)), us_tool->cluster);
1436 us_pulldownmenupos = (INTBIG *)emalloc((count-1) * SIZEOFINTBIG, us_tool->cluster);
1437 if (us_pulldowns == 0 || us_pulldownmenupos == 0) return;
1438 us_pulldownmenucount = count-1;
1439 }
1440
1441 /* load the menubar information */
1442 for(i=1; i<count; i++)
1443 {
1444 /* check out the name of the pop-up menu */
1445 pm = us_getpopupmenu(par[i]);
1446 if (pm == NOPOPUPMENU)
1447 {
1448 ttyputbadusage(x_("menu setmenubar"));
1449 return;
1450 }
1451 us_pulldowns[i-1] = pm;
1452 us_validatemenu(pm);
1453 }
1454
1455 /* always use native menu handling */
1456 nativemenuload(count-1, &par[1]);
1457 return;
1458 }
1459
1460 /* see if new fixed menu location has been specified */
1461 position = us_menupos;
1462 x = us_menux; y = us_menuy;
1463 if (namesamen(pp, x_("top"), l) == 0 && l >= 1)
1464 {
1465 position = 0;
1466 count--; par++;
1467 } else if (namesamen(pp, x_("bottom"), l) == 0 && l >= 1)
1468 {
1469 position = 1;
1470 count--; par++;
1471 } else if (namesamen(pp, x_("left"), l) == 0 && l >= 1)
1472 {
1473 position = 2;
1474 count--; par++;
1475 } else if (namesamen(pp, x_("right"), l) == 0 && l >= 1)
1476 {
1477 position = 3;
1478 count--; par++;
1479 }
1480
1481 /* check for new fixed menu size */
1482 autoset = FALSE;
1483 if (count > 0)
1484 {
1485 if (namesamen(par[0], x_("size"), estrlen(par[0])) != 0)
1486 {
1487 ttyputbadusage(x_("menu"));
1488 return;
1489 }
1490 if (count == 2 && namesamen(par[1], x_("auto"), estrlen(par[1])) == 0)
1491 {
1492 autoset = TRUE;
1493 arctot = pintot = comptot = puretot = 0;
1494 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1495 {
1496 if ((ap->userbits&ANOTUSED) != 0) continue;
1497 np = getpinproto(ap);
1498 if (np != NONODEPROTO && (np->userbits & NNOTUSED) != 0) continue;
1499 arctot++;
1500 }
1501 for(np = el_curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1502 {
1503 if ((np->userbits & NNOTUSED) != 0) continue;
1504 fun = (np->userbits&NFUNCTION) >> NFUNCTIONSH;
1505 if (fun == NPPIN) pintot++; else
1506 if (fun == NPNODE) puretot++; else
1507 comptot++;
1508 }
1509 if (pintot + comptot == 0) pintot = puretot;
1510 x = arctot + pintot + comptot + 1; y = 1;
1511 if (x > 40)
1512 {
1513 x = (x+2) / 3;
1514 y = 3;
1515 } else if (x > 20)
1516 {
1517 x = (x+1) / 2;
1518 y = 2;
1519 }
1520 if (position > 1) { i = x; x = y; y = i; }
1521 } else if (count == 3)
1522 {
1523 x = eatoi(par[1]);
1524 y = eatoi(par[2]);
1525 if (x <= 0 || y <= 0)
1526 {
1527 us_abortcommand(_("Menu sizes must be positive numbers"));
1528 return;
1529 }
1530 } else
1531 {
1532 ttyputusage(x_("menu size (ROWS COLUMNS) | auto"));
1533 return;
1534 }
1535 }
1536
1537 /* set the fixed menu up */
1538 if (x == us_menux && y == us_menuy && position == us_menupos &&
1539 (us_tool->toolstate&MENUON) != 0 && !autoset)
1540 {
1541 ttyputverbose(M_("Menu has not changed"));
1542 return;
1543 }
1544
1545 if (position != us_menupos) resetpaletteparameters();
1546 startobjectchange((INTBIG)us_tool, VTOOL);
1547 if (x != us_menux || y != us_menuy || position != us_menupos || autoset)
1548 us_setmenusize(x, y, position, autoset);
1549 if ((us_tool->toolstate&MENUON) == 0)
1550 (void)setval((INTBIG)us_tool, VTOOL, x_("toolstate"), us_tool->toolstate|MENUON, VINTEGER);
1551 endobjectchange((INTBIG)us_tool, VTOOL);
1552 }
1553
us_mirror(INTBIG count,CHAR * par[])1554 void us_mirror(INTBIG count, CHAR *par[])
1555 {
1556 REGISTER NODEINST *ni, *theni, *subni, **nilist, **newnilist;
1557 REGISTER INTBIG amt, gamt, i;
1558 REGISTER INTBIG nicount, lx, hx, ly, hy, dist, bestdist, aicount, newnicount;
1559 REGISTER CHAR *pt;
1560 REGISTER VARIABLE *var, *tempvar;
1561 REGISTER ARCINST *ai, **ailist, **newailist;
1562 REGISTER NODEPROTO *np;
1563 REGISTER PORTPROTO *thepp, *pp;
1564 REGISTER GEOM **list, *geom;
1565 REGISTER HIGHLIGHT *high;
1566 XARRAY transtz, rot, transfz, t1, t2;
1567 INTBIG gx, gy, cx, cy, x, y, thex, they, tempcenter[2];
1568 extern COMCOMP us_mirrorp;
1569
1570 list = us_gethighlighted(WANTARCINST|WANTNODEINST, 0, 0);
1571 if (list[0] == NOGEOM)
1572 {
1573 us_abortcommand(_("Must select objects to mirror"));
1574 return;
1575 }
1576 np = geomparent(list[0]);
1577
1578 /* figure out which nodes get mirrored */
1579 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1580 ni->temp1 = 0;
1581 for(i=0; list[i] != NOGEOM; i++)
1582 {
1583 geom = list[i];
1584 if (geom->entryisnode)
1585 {
1586 ni = geom->entryaddr.ni;
1587 if (us_cantedit(np, ni, TRUE)) continue;
1588 ni->temp1 = 1;
1589 } else
1590 {
1591 if (us_cantedit(np, NONODEINST, TRUE)) return;
1592 ai = geom->entryaddr.ai;
1593 ai->end[0].nodeinst->temp1 = 1;
1594 ai->end[1].nodeinst->temp1 = 1;
1595 }
1596 }
1597
1598 /* find the one node that is to be mirrored */
1599 nicount = 0;
1600 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1601 {
1602 if (ni->temp1 == 0) continue;
1603 if (nicount == 0)
1604 {
1605 lx = ni->lowx; hx = ni->highx;
1606 ly = ni->lowy; hy = ni->highy;
1607 } else
1608 {
1609 if (ni->lowx < lx) lx = ni->lowx;
1610 if (ni->highx > hx) hx = ni->highx;
1611 if (ni->lowy < ly) ly = ni->lowy;
1612 if (ni->highy > hy) hy = ni->highy;
1613 }
1614 theni = ni;
1615 nicount++;
1616 }
1617 if (nicount > 1)
1618 {
1619 /* multiple nodes: find the center one */
1620 theni = NONODEINST;
1621 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1622 {
1623 if (ni->temp1 == 0) continue;
1624 dist = computedistance((lx+hx)/2, (ly+hy)/2, (ni->lowx+ni->highx)/2,
1625 (ni->lowy+ni->highy)/2);
1626
1627 /* LINTED "bestdist" used in proper order */
1628 if (theni == NONODEINST || dist < bestdist)
1629 {
1630 theni = ni;
1631 bestdist = dist;
1632 }
1633 }
1634 }
1635
1636 if (count == 0)
1637 {
1638 count = ttygetparam(M_("Horizontally or vertically? "), &us_mirrorp, MAXPARS, par);
1639 if (count == 0)
1640 {
1641 us_abortedmsg();
1642 return;
1643 }
1644 }
1645 pt = par[0];
1646 if (*pt != 'h' && *pt != 'v')
1647 {
1648 ttyputusage(x_("mirror horizontal|vertical"));
1649 return;
1650 }
1651
1652 /* determine amount of rotation to effect the mirror */
1653 if (*pt == 'h')
1654 {
1655 if (theni->transpose == 0) amt = 2700; else amt = 900;
1656 } else
1657 {
1658 if (theni->transpose == 0) amt = 900; else amt = 2700;
1659 }
1660
1661 /* determine translation when mirroring about grab or trace point */
1662 if (count >= 2) i = estrlen(par[1]);
1663 tempvar = NOVARIABLE;
1664 if (count >= 2 && namesamen(par[1], x_("sensibly"), i) == 0)
1665 {
1666 if (nicount == 1)
1667 {
1668 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
1669 {
1670 par[1] = x_("about-trace-point");
1671 } else
1672 {
1673 var = getvalkey((INTBIG)theni->proto, VNODEPROTO, VINTEGER|VISARRAY, el_prototype_center_key);
1674 if (var != NOVARIABLE)
1675 {
1676 par[1] = x_("about-grab-point");
1677 } else
1678 {
1679 /* special cases: schematic primitives should mirror sensibly */
1680 if (theni->proto->primindex != 0 && theni->proto->tech == sch_tech)
1681 {
1682 if (theni->proto == sch_transistorprim ||
1683 theni->proto == sch_transistor4prim)
1684 {
1685 tempcenter[0] = 0;
1686 tempcenter[1] = -(theni->proto->highy - theni->proto->lowy) / 2;
1687 tempvar = setvalkey((INTBIG)theni->proto, VNODEPROTO, el_prototype_center_key,
1688 (INTBIG)tempcenter, VINTEGER|VISARRAY|(2<<VLENGTHSH));
1689 par[1] = x_("about-grab-point");
1690 } else if (theni->proto == sch_gndprim)
1691 {
1692 tempcenter[0] = 0;
1693 tempcenter[1] = (theni->proto->highy - theni->proto->lowy) / 2;
1694 tempvar = setvalkey((INTBIG)theni->proto, VNODEPROTO, el_prototype_center_key,
1695 (INTBIG)tempcenter, VINTEGER|VISARRAY|(2<<VLENGTHSH));
1696 par[1] = x_("about-grab-point");
1697 }
1698 }
1699 }
1700 }
1701 }
1702 }
1703 if (count >= 2 && namesamen(par[1], x_("about-grab-point"), i) == 0 && i >= 7)
1704 {
1705 if (nicount != 1)
1706 {
1707 us_abortcommand(_("Must select 1 node to mirror about its grab point"));
1708 return;
1709 }
1710
1711 /* find the grab point */
1712 corneroffset(theni, theni->proto, theni->rotation, theni->transpose, &gx, &gy, FALSE);
1713 gx += theni->lowx; gy += theni->lowy;
1714
1715 /* build transformation for this operation */
1716 transid(transtz); transtz[2][0] = -gx; transtz[2][1] = -gy;
1717 if (*pt == 'h') gamt = 2700; else gamt = 900;
1718 makeangle(gamt, 1, rot);
1719 transid(transfz); transfz[2][0] = gx; transfz[2][1] = gy;
1720 transmult(transtz, rot, t1);
1721 transmult(t1, transfz, t2);
1722
1723 /* find out where true center moves */
1724 cx = (theni->lowx+theni->highx)/2; cy = (theni->lowy+theni->highy)/2;
1725 xform(cx, cy, &gx, &gy, t2);
1726 gx -= cx; gy -= cy;
1727 if (tempvar != NOVARIABLE)
1728 (void)delvalkey((INTBIG)theni->proto, VNODEPROTO, el_prototype_center_key);
1729 } else if (count >= 2 && namesamen(par[1], x_("about-trace-point"), i) == 0 && i >= 7)
1730 {
1731 if (nicount != 1)
1732 {
1733 us_abortcommand(_("Must select 1 node to mirror about its outline point"));
1734 return;
1735 }
1736
1737 /* get the trace information */
1738 var = gettrace(theni);
1739 if (var == NOVARIABLE)
1740 {
1741 us_abortcommand(_("Highlighted node must have outline information"));
1742 return;
1743 }
1744
1745 /* find the pivot point */
1746 high = us_getonehighlight();
1747 i = high->frompoint; if (i != 0) i--;
1748 makerot(theni, t1);
1749 gx = (theni->highx + theni->lowx) / 2;
1750 gy = (theni->highy + theni->lowy) / 2;
1751 xform(((INTBIG *)var->addr)[i*2]+gx, ((INTBIG *)var->addr)[i*2+1]+gy, &gx, &gy, t1);
1752
1753 /* build transformation for this operation */
1754 transid(transtz); transtz[2][0] = -gx; transtz[2][1] = -gy;
1755 if (*pt == 'h') gamt = 2700; else gamt = 900;
1756 makeangle(gamt, 1, rot);
1757 transid(transfz); transfz[2][0] = gx; transfz[2][1] = gy;
1758 transmult(transtz, rot, t1);
1759 transmult(t1, transfz, t2);
1760
1761 /* find out where true center moves */
1762 cx = (theni->lowx+theni->highx)/2; cy = (theni->lowy+theni->highy)/2;
1763 xform(cx, cy, &gx, &gy, t2);
1764 gx -= cx; gy -= cy;
1765 } else gx = gy = 0;
1766
1767 /* now make sure that it is all connected */
1768 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1769 ai->userbits &= ~ARCFLAGBIT;
1770 aicount = newnicount = 0;
1771 for(;;)
1772 {
1773 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1774 ni->userbits &= ~NODEFLAGBIT;
1775 us_nettravel(theni, NODEFLAGBIT);
1776 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1777 {
1778 if (ni->temp1 == 0) continue;
1779 if ((ni->userbits&NODEFLAGBIT) == 0) break;
1780 }
1781 if (ni == NONODEINST) break;
1782
1783 /* this node is unconnected: connect it */
1784 thepp = theni->proto->firstportproto;
1785 if (thepp == NOPORTPROTO)
1786 {
1787 /* no port on the cell: create one */
1788 subni = newnodeinst(gen_univpinprim, theni->proto->lowx, theni->proto->highx,
1789 theni->proto->lowy, theni->proto->highy, 0, 0, theni->proto);
1790 if (subni == NONODEINST) break;
1791 thepp = newportproto(theni->proto, subni, subni->proto->firstportproto, x_("temp"));
1792
1793 /* add to the list of temporary nodes */
1794 newnilist = (NODEINST **)emalloc((newnicount+1) * (sizeof (NODEINST *)), el_tempcluster);
1795 if (newnilist == 0) break;
1796
1797 /* LINTED "nilist" used in proper order */
1798 for(i=0; i<newnicount; i++) newnilist[i] = nilist[i];
1799 if (newnicount > 0) efree((CHAR *)nilist);
1800 nilist = newnilist;
1801 nilist[newnicount] = subni;
1802 newnicount++;
1803 }
1804 pp = ni->proto->firstportproto;
1805 portposition(theni, thepp, &thex, &they);
1806 portposition(ni, pp, &x, &y);
1807 ai = newarcinst(gen_invisiblearc, 0, 0, theni, thepp, thex, they,
1808 ni, pp, x, y, np);
1809 if (ai == NOARCINST) break;
1810
1811 /* add to the list of temporary arcs */
1812 newailist = (ARCINST **)emalloc((aicount+1) * (sizeof (ARCINST *)), el_tempcluster);
1813 if (newailist == 0) break;
1814
1815 /* LINTED "ailist" used in proper order */
1816 for(i=0; i<aicount; i++) newailist[i] = ailist[i];
1817 if (aicount > 0) efree((CHAR *)ailist);
1818 ailist = newailist;
1819 ailist[aicount] = ai;
1820 aicount++;
1821 }
1822
1823 /* save highlighting */
1824 us_pushhighlight();
1825 us_clearhighlightcount();
1826
1827 /* set arc constraints appropriately */
1828 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1829 {
1830 if (ai->end[0].nodeinst->temp1 != 0 && ai->end[1].nodeinst->temp1 != 0)
1831 {
1832 /* arc connecting two mirrored nodes: make rigid */
1833 (void)(*el_curconstraint->setobject)((INTBIG)ai, VARCINST, CHANGETYPETEMPRIGID, 0);
1834 }
1835 }
1836
1837 /* mirror the node */
1838 startobjectchange((INTBIG)theni, VNODEINST);
1839 modifynodeinst(theni, gx, gy, gx, gy, amt, 1-theni->transpose*2);
1840 endobjectchange((INTBIG)theni, VNODEINST);
1841
1842 /* delete intermediate arcs used to constrain */
1843 for(i=0; i<aicount; i++)
1844 (void)killarcinst(ailist[i]);
1845 if (aicount > 0) efree((CHAR *)ailist);
1846
1847 /* delete intermediate nodes used to constrain */
1848 for(i=0; i<newnicount; i++)
1849 {
1850 (void)killportproto(nilist[i]->parent, nilist[i]->firstportexpinst->exportproto);
1851 (void)killnodeinst(nilist[i]);
1852 }
1853 if (newnicount > 0) efree((CHAR *)nilist);
1854
1855 /* restore highlighting */
1856 us_pophighlight(TRUE);
1857
1858 if (*pt == 'h') ttyputverbose(M_("Node mirrored horizontally")); else
1859 ttyputverbose(M_("Node mirrored vertically"));
1860 }
1861
1862 static DIALOGITEM us_movebydialogitems[] =
1863 {
1864 /* 1 */ {0, {64,96,88,160}, BUTTON, N_("OK")},
1865 /* 2 */ {0, {64,8,88,72}, BUTTON, N_("Cancel")},
1866 /* 3 */ {0, {8,48,24,142}, EDITTEXT, x_("")},
1867 /* 4 */ {0, {8,20,24,42}, MESSAGE, N_("dX:")},
1868 /* 5 */ {0, {32,48,48,142}, EDITTEXT, x_("")},
1869 /* 6 */ {0, {32,20,48,42}, MESSAGE, N_("dY:")}
1870 };
1871 static DIALOG us_movebydialog = {{50,75,147,244}, N_("Move By Amount"), 0, 6, us_movebydialogitems, 0, 0};
1872
1873 /* special items for the "move by" dialog: */
1874 #define DMVB_XBY 3 /* X change (edit text) */
1875 #define DMVB_XBY_L 4 /* X change label (stat text) */
1876 #define DMVB_YBY 5 /* Y change (edit text) */
1877 #define DMVB_YBY_L 6 /* Y change label (stat text) */
1878
us_move(INTBIG count,CHAR * par[])1879 void us_move(INTBIG count, CHAR *par[])
1880 {
1881 REGISTER NODEINST *ni, **nodelist;
1882 REGISTER NODEPROTO *np;
1883 REGISTER ARCINST *ai;
1884 REGISTER INTBIG ang;
1885 static INTBIG movebyx = 0, movebyy = 0;
1886 REGISTER INTBIG l, total, i, wid, len, itemHit, amt;
1887 INTBIG numtexts, snapx, snapy, bestlx, bestly, lx, hx, ly, hy,
1888 dx, dy, xcur, ycur, p1x, p1y, p2x, p2y;
1889 REGISTER GEOM **list;
1890 HIGHLIGHT thishigh, otherhigh;
1891 BOOLEAN centeredprimitives;
1892 REGISTER CHAR *pp;
1893 CHAR **textlist;
1894 static POLYGON *poly = NOPOLYGON;
1895 REGISTER VARIABLE *var;
1896 REGISTER void *dia;
1897
1898 /* get polygon */
1899 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1900
1901 /* make sure there is a current cell */
1902 np = us_needcell();
1903 if (np == NONODEPROTO) return;
1904
1905 /* get the objects to be moved (mark nodes with nonzero "temp1") */
1906 list = us_gethighlighted(WANTNODEINST | WANTARCINST, &numtexts, &textlist);
1907
1908 if (list[0] == NOGEOM && numtexts == 0)
1909 {
1910 us_abortcommand(_("First select objects to move"));
1911 return;
1912 }
1913
1914 /* make sure they are all in the same cell */
1915 for(i=0; list[i] != NOGEOM; i++) if (np != geomparent(list[i]))
1916 {
1917 us_abortcommand(_("All moved objects must be in the same cell"));
1918 return;
1919 }
1920
1921 /* count the number of nodes */
1922 for(total=0, ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1923 {
1924 if (ni->temp1 == 0) continue;
1925 if (us_cantedit(np, ni, TRUE)) return;
1926 total++;
1927 }
1928 if (total == 0 && numtexts == 0) return;
1929
1930 /* build a list that includes all nodes touching moved arcs */
1931 if (total > 0)
1932 {
1933 nodelist = (NODEINST **)emalloc((total * (sizeof (NODEINST *))), el_tempcluster);
1934 if (nodelist == 0) return;
1935 for(i=0, ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1936 if (ni->temp1 != 0) nodelist[i++] = ni;
1937 }
1938
1939 if (count > 0)
1940 {
1941 l = estrlen(pp = par[0]);
1942 if (namesamen(pp, x_("valign"), l) == 0 && l >= 1)
1943 {
1944 /* handle vertical alignment */
1945 if (count < 2) ttyputusage(x_("move valign EDGE")); else
1946 {
1947 l = estrlen(pp = par[1]);
1948 if (namesamen(pp, x_("top"), l) == 0 && l >= 1)
1949 {
1950 us_alignnodes(total, nodelist, FALSE, 0);
1951 } else if (namesamen(pp, x_("bottom"), l) == 0 && l >= 1)
1952 {
1953 us_alignnodes(total, nodelist, FALSE, 1);
1954 } else if (namesamen(pp, x_("center"), l) == 0 && l >= 1)
1955 {
1956 us_alignnodes(total, nodelist, FALSE, 2);
1957 } else ttyputbadusage(x_("move valign"));
1958 }
1959 if (total > 0) efree((CHAR *)nodelist);
1960 return;
1961 }
1962 if (namesamen(pp, x_("halign"), l) == 0 && l >= 1)
1963 {
1964 /* handle horizontal alignment */
1965 if (count < 2) ttyputusage(x_("move halign EDGE")); else
1966 {
1967 l = estrlen(pp = par[1]);
1968 if (namesamen(pp, x_("left"), l) == 0 && l >= 1)
1969 {
1970 us_alignnodes(total, nodelist, TRUE, 0);
1971 } else if (namesamen(pp, x_("right"), l) == 0 && l >= 1)
1972 {
1973 us_alignnodes(total, nodelist, TRUE, 1);
1974 } else if (namesamen(pp, x_("center"), l) == 0 && l >= 1)
1975 {
1976 us_alignnodes(total, nodelist, TRUE, 2);
1977 } else ttyputbadusage(x_("move halign"));
1978 }
1979 if (total > 0) efree((CHAR *)nodelist);
1980 return;
1981 }
1982 }
1983
1984 /* figure out lower-left corner of this collection of objects */
1985 if (total == 0)
1986 {
1987 bestlx = (np->lowx + np->highx) / 2;
1988 bestly = (np->lowy + np->highy) / 2;
1989 } else
1990 {
1991 us_getlowleft(nodelist[0], &bestlx, &bestly);
1992 }
1993 for(i=1; i<total; i++)
1994 {
1995 us_getlowleft(nodelist[i], &lx, &ly);
1996 if (lx < bestlx) bestlx = lx;
1997 if (ly < bestly) bestly = ly;
1998 }
1999 for(i=0; list[i] != NOGEOM; i++) if (!list[i]->entryisnode)
2000 {
2001 ai = list[i]->entryaddr.ai;
2002 wid = ai->width - arcwidthoffset(ai);
2003 makearcpoly(ai->length, wid, ai, poly, FILLED);
2004 getbbox(poly, &lx, &hx, &ly, &hy);
2005 if (lx < bestlx) bestlx = lx;
2006 if (ly < bestly) bestly = ly;
2007 }
2008
2009 /* special case when moving one node: account for cell center */
2010 if (total == 1 && list[1] == NOGEOM && numtexts == 0)
2011 {
2012 /* get standard corner offset */
2013 ni = nodelist[0];
2014 if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
2015 centeredprimitives = FALSE;
2016 corneroffset(ni, ni->proto, ni->rotation, ni->transpose, &lx, &ly,
2017 centeredprimitives);
2018 bestlx = ni->lowx + lx;
2019 bestly = ni->lowy + ly;
2020 }
2021
2022 /* special case if there is exactly one snap point */
2023 if (us_getonesnappoint(&snapx, &snapy))
2024 {
2025 bestlx = snapx; bestly = snapy;
2026 }
2027
2028 /* special case if two objects are selected with snap points */
2029 if (count == 0)
2030 {
2031 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
2032 if (var != NOVARIABLE)
2033 {
2034 len = getlength(var);
2035 if (len == 2)
2036 {
2037 if (!us_makehighlight(((CHAR **)var->addr)[0], &thishigh) &&
2038 !us_makehighlight(((CHAR **)var->addr)[1], &otherhigh))
2039 {
2040 /* describe these two objects */
2041 if ((thishigh.status&HIGHSNAP) != 0 && (otherhigh.status&HIGHSNAP) != 0)
2042 {
2043 /* move first to second */
2044 us_getsnappoint(&thishigh, &p1x, &p1y);
2045 us_getsnappoint(&otherhigh, &p2x, &p2y);
2046 dx = p2x - p1x;
2047 dy = p2y - p1y;
2048 if (dx == 0 && dy == 0)
2049 {
2050 us_abortcommand(_("Points are already aligned"));
2051 if (total > 0) efree((CHAR *)nodelist);
2052 return;
2053 }
2054 ni = thishigh.fromgeom->entryaddr.ni;
2055 us_pushhighlight();
2056 us_clearhighlightcount();
2057 startobjectchange((INTBIG)ni, VNODEINST);
2058 modifynodeinst(ni, dx, dy, dx, dy, 0, 0);
2059 endobjectchange((INTBIG)ni, VNODEINST);
2060 us_pophighlight(TRUE);
2061 if (total > 0) efree((CHAR *)nodelist);
2062 return;
2063 }
2064 }
2065 }
2066 }
2067 }
2068
2069 /* no arguments: simple motion */
2070 if (count == 0)
2071 {
2072 if ((us_tool->toolstate&INTERACTIVE) != 0)
2073 {
2074 /* interactive motion: track cursor */
2075 us_multidraginit(bestlx, bestly, list, nodelist, total, 0, TRUE);
2076 trackcursor(FALSE, us_ignoreup, us_multidragbegin, us_multidragdown,
2077 us_stoponchar, us_multidragup, TRACKDRAGGING);
2078 if (el_pleasestop != 0)
2079 {
2080 if (total > 0) efree((CHAR *)nodelist);
2081 return;
2082 }
2083 }
2084
2085 /* get co-ordinates of cursor */
2086 if (us_demandxy(&xcur, &ycur))
2087 {
2088 if (total > 0) efree((CHAR *)nodelist);
2089 return;
2090 }
2091 gridalign(&xcur, &ycur, 1, np);
2092
2093 /* make the move if it is valid */
2094 if (xcur == bestlx && ycur == bestly) ttyputverbose(M_("Null motion")); else
2095 {
2096 us_pushhighlight();
2097 us_clearhighlightcount();
2098 us_manymove(list, nodelist, total, xcur-bestlx, ycur-bestly);
2099 us_moveselectedtext(numtexts, textlist, list, xcur-bestlx, ycur-bestly);
2100 us_pophighlight(TRUE);
2101 }
2102 if (total > 0) efree((CHAR *)nodelist);
2103 return;
2104 }
2105
2106 l = estrlen(pp = par[0]);
2107
2108 /* handle absolute motion option "move to X Y" */
2109 if (namesamen(pp, x_("to"), l) == 0 && l >= 1)
2110 {
2111 /* get absolute position to place object */
2112 if (count < 3)
2113 {
2114 ttyputusage(x_("move to X Y"));
2115 if (total > 0) efree((CHAR *)nodelist);
2116 return;
2117 }
2118 xcur = atola(par[1], 0);
2119 ycur = atola(par[2], 0);
2120
2121 /* make the move if it is valid */
2122 if (xcur == bestlx && ycur == bestly) ttyputverbose(M_("Null motion")); else
2123 {
2124 us_pushhighlight();
2125 us_clearhighlightcount();
2126 us_manymove(list, nodelist, total, xcur-bestlx, ycur-bestly);
2127 us_moveselectedtext(numtexts, textlist, list, xcur-bestlx, ycur-bestly);
2128 us_pophighlight(TRUE);
2129 }
2130 if (total > 0) efree((CHAR *)nodelist);
2131 return;
2132 }
2133
2134 /* handle relative motion option "move by X Y" */
2135 if (namesamen(pp, x_("by"), l) == 0 && l >= 1)
2136 {
2137 /* get absolute position to place object */
2138 if (count == 2 && namesamen(par[1], x_("dialog"), estrlen(par[1])) == 0)
2139 {
2140 /* get coordinates from dialog */
2141 dia = DiaInitDialog(&us_movebydialog);
2142 if (dia == 0)
2143 {
2144 if (total > 0) efree((CHAR *)nodelist);
2145 return;
2146 }
2147 DiaSetText(dia, DMVB_XBY, frtoa(movebyx));
2148 DiaSetText(dia, DMVB_YBY, frtoa(movebyy));
2149 for(;;)
2150 {
2151 itemHit = DiaNextHit(dia);
2152 if (itemHit == CANCEL || itemHit == OK) break;
2153 }
2154 movebyx = atofr(DiaGetText(dia, DMVB_XBY));
2155 movebyy = atofr(DiaGetText(dia, DMVB_YBY));
2156 xcur = atola(DiaGetText(dia, DMVB_XBY), 0);
2157 ycur = atola(DiaGetText(dia, DMVB_YBY), 0);
2158 DiaDoneDialog(dia);
2159 if (itemHit == CANCEL)
2160 {
2161 if (total > 0) efree((CHAR *)nodelist);
2162 return;
2163 }
2164 } else
2165 {
2166 /* get coordinates from command line */
2167 if (count < 3)
2168 {
2169 ttyputusage(x_("move by X Y"));
2170 if (total > 0) efree((CHAR *)nodelist);
2171 return;
2172 }
2173 xcur = atola(par[1], 0);
2174 ycur = atola(par[2], 0);
2175 }
2176
2177 /* make the move if it is valid */
2178 if (xcur == 0 && ycur == 0) ttyputverbose(M_("Null motion")); else
2179 {
2180 us_pushhighlight();
2181 us_clearhighlightcount();
2182 us_manymove(list, nodelist, total, xcur, ycur);
2183 us_moveselectedtext(numtexts, textlist, list, xcur, ycur);
2184 us_pophighlight(TRUE);
2185 }
2186 if (total > 0) efree((CHAR *)nodelist);
2187 return;
2188 }
2189
2190 /* handle motion to cursor along an angle: "move angle ANG" */
2191 if (namesamen(pp, x_("angle"), l) == 0 && l >= 1)
2192 {
2193 /* get co-ordinates of cursor */
2194 if (us_demandxy(&xcur, &ycur))
2195 {
2196 if (total > 0) efree((CHAR *)nodelist);
2197 return;
2198 }
2199 gridalign(&xcur, &ycur, 1, np);
2200
2201 /* get angle to align along */
2202 if (count < 2)
2203 {
2204 ttyputusage(x_("move angle ANGLE"));
2205 if (total > 0) efree((CHAR *)nodelist);
2206 return;
2207 }
2208 ang = atofr(par[1])*10/WHOLE;
2209
2210 /* adjust the cursor position if selecting interactively */
2211 if ((us_tool->toolstate&INTERACTIVE) != 0)
2212 {
2213 us_multidraginit(bestlx, bestly, list, nodelist, total, ang, TRUE);
2214 trackcursor(FALSE, us_ignoreup, us_multidragbegin, us_multidragdown,
2215 us_stoponchar, us_multidragup, TRACKDRAGGING);
2216 if (el_pleasestop != 0)
2217 {
2218 if (total > 0) efree((CHAR *)nodelist);
2219 return;
2220 }
2221 if (us_demandxy(&xcur, &ycur))
2222 {
2223 if (total > 0) efree((CHAR *)nodelist);
2224 return;
2225 }
2226 gridalign(&xcur, &ycur, 1, np);
2227 }
2228
2229 /* compute sliding for this highlighting */
2230 us_getslide(ang, bestlx, bestly, xcur, ycur, &dx, &dy);
2231
2232 /* make the move if it is nonnull */
2233 if (dx == bestlx && dy == bestly) ttyputverbose(M_("Null motion")); else
2234 {
2235 us_pushhighlight();
2236 us_clearhighlightcount();
2237 us_manymove(list, nodelist, total, dx-bestlx, dy-bestly);
2238 us_moveselectedtext(numtexts, textlist, list, xcur-bestlx, ycur-bestly);
2239 us_pophighlight(TRUE);
2240 }
2241 if (total > 0) efree((CHAR *)nodelist);
2242 return;
2243 }
2244
2245 /* if direction is specified, get it */
2246 dx = dy = 0;
2247 if (namesamen(pp, x_("up"), l) == 0 && l >= 1)
2248 {
2249 /* in outline edit, this makes no sense */
2250 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
2251 {
2252 if (total > 0) efree((CHAR *)nodelist);
2253 return;
2254 }
2255 if (count < 2) amt = el_curlib->lambda[el_curtech->techindex]; else
2256 {
2257 l = el_units;
2258 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITLAMBDA;
2259 amt = atola(par[1], 0);
2260 el_units = l;
2261 }
2262 dy += amt;
2263 } else if (namesamen(pp, x_("down"), l) == 0 && l >= 1)
2264 {
2265 /* in outline edit, this makes no sense */
2266 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
2267 {
2268 if (total > 0) efree((CHAR *)nodelist);
2269 return;
2270 }
2271 if (count < 2) amt = el_curlib->lambda[el_curtech->techindex]; else
2272 {
2273 l = el_units;
2274 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITLAMBDA;
2275 amt = atola(par[1], 0);
2276 el_units = l;
2277 }
2278 dy -= amt;
2279 } else if (namesamen(pp, x_("left"), l) == 0 && l >= 1)
2280 {
2281 /* in outline edit, change selection to previous point */
2282 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
2283 {
2284 par[0] = x_("trace");
2285 par[1] = x_("prev-point");
2286 us_node(2, par);
2287 if (total > 0) efree((CHAR *)nodelist);
2288 return;
2289 }
2290 if (count < 2) amt = el_curlib->lambda[el_curtech->techindex]; else
2291 {
2292 l = el_units;
2293 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITLAMBDA;
2294 amt = atola(par[1], 0);
2295 el_units = l;
2296 }
2297 dx -= amt;
2298 } else if (namesamen(pp, x_("right"), l) == 0 && l >= 1)
2299 {
2300 /* in outline edit, change selection to next point */
2301 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
2302 {
2303 par[0] = x_("trace");
2304 par[1] = x_("next-point");
2305 us_node(2, par);
2306 if (total > 0) efree((CHAR *)nodelist);
2307 return;
2308 }
2309 if (count < 2) amt = el_curlib->lambda[el_curtech->techindex]; else
2310 {
2311 l = el_units;
2312 el_units = (el_units & ~DISPLAYUNITS) | DISPUNITLAMBDA;
2313 amt = atola(par[1], 0);
2314 el_units = l;
2315 }
2316 dx += amt;
2317 } else
2318 {
2319 ttyputbadusage(x_("move"));
2320 if (total > 0) efree((CHAR *)nodelist);
2321 return;
2322 }
2323
2324 /* transform to space of this window */
2325 if ((el_curwindowpart->state&INPLACEEDIT) != 0)
2326 {
2327 xform(0, 0, &snapx, &snapy, el_curwindowpart->outofcell);
2328 snapx += dx; snapy += dy;
2329 xform(snapx, snapy, &dx, &dy, el_curwindowpart->intocell);
2330 }
2331
2332 /* now move the object */
2333 if (dx != 0 || dy != 0)
2334 {
2335 us_pushhighlight();
2336 us_clearhighlightcount();
2337 us_manymove(list, nodelist, total, dx, dy);
2338 us_moveselectedtext(numtexts, textlist, list, dx, dy);
2339 us_pophighlight(TRUE);
2340 }
2341 if (total > 0) efree((CHAR *)nodelist);
2342 }
2343
us_node(INTBIG count,CHAR * par[])2344 void us_node(INTBIG count, CHAR *par[])
2345 {
2346 REGISTER INTBIG amt, i, *newlist, x, y, curlamb, inside, outside, l, negated, size, nogood,
2347 total, addpoint, deletepoint, whichpoint, p, movepoint, pointgiven, segs, degs,
2348 nextpoint, prevpoint;
2349 BOOLEAN waitfordown, stillok;
2350 XARRAY trans;
2351 INTBIG d[2], xcur, ycur, initlist[8];
2352 REGISTER CHAR *pt, *ch;
2353 REGISTER GEOM **list;
2354 extern COMCOMP us_nodep;
2355 REGISTER TECHNOLOGY *tech;
2356 REGISTER NODEPROTO *np;
2357 REGISTER NODEINST *ni, *store;
2358 REGISTER HIGHLIGHT *high;
2359 HIGHLIGHT newhigh;
2360 REGISTER VARIABLE *var;
2361
2362 /* disallow node modification if lock is on */
2363 np = us_needcell();
2364 if (np == NONODEPROTO) return;
2365
2366 if (count == 0)
2367 {
2368 count = ttygetparam(M_("Node option: "), &us_nodep, MAXPARS, par);
2369 if (count == 0)
2370 {
2371 us_abortedmsg();
2372 return;
2373 }
2374 }
2375 l = estrlen(pt = par[0]);
2376
2377 /* handle negation */
2378 if (namesamen(pt, x_("not"), l) == 0 && l >= 2)
2379 {
2380 negated = 1;
2381 count--;
2382 par++;
2383 l = estrlen(pt = par[0]);
2384 } else negated = 0;
2385
2386 if (namesamen(pt, x_("expand"), l) == 0 && l >= 1)
2387 {
2388 if (count < 2) amt = MAXINTBIG; else amt = eatoi(par[1]);
2389 list = us_gethighlighted(WANTNODEINST, 0, 0);
2390 if (list[0] == NOGEOM)
2391 {
2392 us_abortcommand(_("Select nodes to be expanded"));
2393 return;
2394 }
2395
2396 /* save highlighting */
2397 us_pushhighlight();
2398 us_clearhighlightcount();
2399
2400 /* pre-compute */
2401 for(i=0; list[i] != NOGEOM; i++)
2402 {
2403 ni = list[i]->entryaddr.ni;
2404 if (negated)
2405 {
2406 if ((ni->userbits & NEXPAND) != 0)
2407 (void)us_setunexpand(ni, amt);
2408 }
2409 startobjectchange((INTBIG)ni, VNODEINST);
2410 }
2411
2412 /* do the change */
2413 for(i=0; list[i] != NOGEOM; i++)
2414 {
2415 ni = list[i]->entryaddr.ni;
2416 if (negated == 0) us_doexpand(ni, amt, 0); else
2417 us_dounexpand(ni);
2418 }
2419
2420 /* post-draw */
2421 for(i=0; list[i] != NOGEOM; i++)
2422 {
2423 ni = list[i]->entryaddr.ni;
2424 endobjectchange((INTBIG)ni, VNODEINST);
2425 }
2426
2427 /* restore highlighting */
2428 us_pophighlight(FALSE);
2429 return;
2430 }
2431
2432 if (namesamen(pt, x_("name"), l) == 0 && l >= 2)
2433 {
2434 ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
2435 if (ni == NONODEINST) return;
2436
2437 if (negated == 0)
2438 {
2439 if (count < 2)
2440 {
2441 ttyputusage(x_("node name NODENAME"));
2442 return;
2443 }
2444 ch = par[1];
2445
2446 /* sensibility check for multiple nodes with the same name */
2447 for(store = ni->parent->firstnodeinst; store != NONODEINST; store = store->nextnodeinst)
2448 {
2449 if (store == ni) continue;
2450 var = getvalkey((INTBIG)store, VNODEINST, VSTRING, el_node_name_key);
2451 if (var == NOVARIABLE) continue;
2452 if (namesame(ch, (CHAR *)var->addr) == 0)
2453 {
2454 ttyputmsg(_("Warning: already a node in this cell called %s"), ch);
2455 break;
2456 }
2457 }
2458 }
2459
2460 /* save highlighting */
2461 us_pushhighlight();
2462 us_clearhighlightcount();
2463
2464 /* change the name of the nodeinst */
2465 startobjectchange((INTBIG)ni, VNODEINST);
2466 if (negated != 0) (void)delvalkey((INTBIG)ni, VNODEINST, el_node_name_key); else
2467 {
2468 var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)ch, VSTRING|VDISPLAY);
2469 if (var != NOVARIABLE)
2470 {
2471 defaulttextsize(3, var->textdescript);
2472
2473 /* shift text down if on a cell instance */
2474 if (ni->proto->primindex == 0)
2475 {
2476 us_setdescriptoffset(var->textdescript,
2477 0, (ni->highy-ni->lowy) / el_curlib->lambda[el_curtech->techindex]);
2478 }
2479 }
2480 }
2481 endobjectchange((INTBIG)ni, VNODEINST);
2482
2483 /* restore highlighting */
2484 us_pophighlight(FALSE);
2485
2486 /* report results and quit */
2487 if (negated != 0) ttyputverbose(M_("Node name removed")); else
2488 ttyputverbose(M_("Node name is '%s'"), ch);
2489 return;
2490 }
2491
2492 /* everything after this point is structural and must check for locks */
2493 if (us_cantedit(np, NONODEINST, TRUE)) return;
2494
2495 if (namesamen(pt, x_("cover-implant"), l) == 0 && l >= 1)
2496 {
2497 us_coverimplant();
2498 return;
2499 }
2500
2501 if (namesamen(pt, x_("regrid-selected"), l) == 0 && l >= 1)
2502 {
2503 us_regridselected();
2504 return;
2505 }
2506
2507 if (namesamen(pt, x_("trace"), l) == 0 && l >= 1)
2508 {
2509 /* special case for converting text to layout */
2510 if (count < 2)
2511 {
2512 ttyputusage(x_("node trace OPTIONS"));
2513 return;
2514 }
2515 l = estrlen(pt = par[1]);
2516 if (namesamen(pt, x_("init-points"), l) == 0 && l >= 1)
2517 {
2518 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2519 if (store == NONODEINST) return;
2520 if ((store->proto->userbits&HOLDSTRACE) == 0)
2521 {
2522 us_abortcommand(_("Sorry, %s nodes cannot hold outline information"),
2523 describenodeproto(store->proto));
2524 return;
2525 }
2526 if (store->proto == art_openedpolygonprim || store->proto == art_openeddottedpolygonprim ||
2527 store->proto == art_openeddashedpolygonprim || store->proto == art_openedthickerpolygonprim ||
2528 store->proto == art_splineprim)
2529 {
2530 x = (store->lowx + store->highx) / 2;
2531 y = (store->lowy + store->highy) / 2;
2532 tech = store->parent->tech;
2533 curlamb = store->parent->lib->lambda[tech->techindex];
2534 initlist[0] = x - curlamb * 3;
2535 initlist[1] = y - curlamb * 3;
2536 initlist[2] = x - curlamb;
2537 initlist[3] = y + curlamb * 3;
2538 initlist[4] = x + curlamb;
2539 initlist[5] = y - curlamb * 3;
2540 initlist[6] = x + curlamb * 3;
2541 initlist[7] = y + curlamb * 3;
2542 us_pushhighlight();
2543 us_clearhighlightcount();
2544 us_settrace(store, initlist, 4);
2545 us_pophighlight(FALSE);
2546 } else if (store->proto == art_closedpolygonprim || store->proto == art_filledpolygonprim)
2547 {
2548 x = (store->lowx + store->highx) / 2;
2549 y = (store->lowy + store->highy) / 2;
2550 tech = store->parent->tech;
2551 curlamb = store->parent->lib->lambda[tech->techindex];
2552 initlist[0] = x;
2553 initlist[1] = y - curlamb * 3;
2554 initlist[2] = x - curlamb * 3;
2555 initlist[3] = y;
2556 initlist[4] = x;
2557 initlist[5] = y + curlamb * 3;
2558 initlist[6] = x + curlamb * 3;
2559 initlist[7] = y - curlamb * 3;
2560 us_pushhighlight();
2561 us_clearhighlightcount();
2562 us_settrace(store, initlist, 4);
2563 us_pophighlight(FALSE);
2564 }
2565 return;
2566 }
2567 if (namesamen(pt, x_("place-text"), l) == 0 && l >= 2)
2568 {
2569 if (count < 10)
2570 {
2571 ttyputusage(x_("node trace place-text LAYER SIZE FONT ITALIC BOLD UNDERLINE SEPARATION MESSAGE"));
2572 return;
2573 }
2574 us_layouttext(par[2], eatoi(par[3]), 1, eatoi(par[4]), eatoi(par[5]),
2575 eatoi(par[6]), eatoi(par[7]), eatoi(par[8]), par[9]);
2576 return;
2577 }
2578
2579 /* special case for filleting */
2580 if (namesamen(pt, x_("fillet"), l) == 0)
2581 {
2582 us_dofillet();
2583 return;
2584 }
2585
2586 /* special case for annulus construction */
2587 if (namesamen(pt, x_("construct-annulus"), l) == 0)
2588 {
2589 if (count < 4)
2590 {
2591 ttyputusage(x_("node trace construct-annulus INSIDE OUTSIDE [RESOLUTION] [DEGREES]"));
2592 return;
2593 }
2594 inside = atola(par[2], 0);
2595 outside = atola(par[3], 0);
2596 segs = 16;
2597 if (count >= 5) segs = myatoi(par[4]);
2598 if (segs < 4) segs = 4;
2599 degs = 3600;
2600 if (count >= 6) degs = atofr(par[5])*10/WHOLE;
2601 if (degs <= 0) degs = 3600;
2602 if (degs > 3600) degs = 3600;
2603
2604 /* make sure node can handle trace information */
2605 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2606 if (store == NONODEINST) return;
2607 if ((store->proto->userbits&HOLDSTRACE) == 0)
2608 {
2609 us_abortcommand(_("Sorry, %s nodes cannot hold outline information"),
2610 describenodeproto(store->proto));
2611 return;
2612 }
2613
2614 /* allocate space for the trace */
2615 newlist = emalloc(((segs+1)*4*SIZEOFINTBIG), el_tempcluster);
2616 if (newlist == 0)
2617 {
2618 ttyputnomemory();
2619 return;
2620 }
2621
2622 l = 0;
2623 if (inside > 0)
2624 {
2625 for(i=0; i<=segs; i++)
2626 {
2627 p = degs*i/segs;
2628 x = mult(inside, cosine(p)) + (store->lowx+store->highx)/2;
2629 y = mult(inside, sine(p)) + (store->lowy+store->highy)/2;
2630 newlist[l++] = x; newlist[l++] = y;
2631 }
2632 }
2633 for(i=segs; i>=0; i--)
2634 {
2635 p = degs*i/segs;
2636 x = mult(outside, cosine(p)) + (store->lowx+store->highx)/2;
2637 y = mult(outside, sine(p)) + (store->lowy+store->highy)/2;
2638 newlist[l++] = x; newlist[l++] = y;
2639 }
2640
2641 /* save highlighting, set trace, restore highlighting */
2642 us_pushhighlight();
2643 us_clearhighlightcount();
2644 us_settrace(store, newlist, l/2);
2645 us_pophighlight(FALSE);
2646 efree((CHAR *)newlist);
2647 return;
2648 }
2649
2650 /* parse the options */
2651 store = NONODEINST;
2652 waitfordown = FALSE;
2653 addpoint = deletepoint = movepoint = pointgiven = nextpoint = prevpoint = 0;
2654 for(i=1; i<count; i++)
2655 {
2656 l = estrlen(pt = par[i]);
2657
2658 if (namesamen(pt, x_("store-trace"), l) == 0 && l >= 1)
2659 {
2660 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2661 if (store == NONODEINST) return;
2662 } else if (namesamen(pt, x_("add-point"), l) == 0 && l >= 1)
2663 {
2664 addpoint++;
2665 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2666 if (store == NONODEINST) return;
2667 high = us_getonehighlight();
2668 whichpoint = high->frompoint;
2669 if (count > i+2 && isanumber(par[i+1]) && isanumber(par[i+2]))
2670 {
2671 xcur = atola(par[i+1], 0);
2672 ycur = atola(par[i+2], 0);
2673 i += 2;
2674 pointgiven++;
2675 }
2676 } else if (namesamen(pt, x_("move-point"), l) == 0 && l >= 1)
2677 {
2678 movepoint++;
2679 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2680 if (store == NONODEINST) return;
2681 high = us_getonehighlight();
2682 whichpoint = high->frompoint;
2683 if (count > i+2 && isanumber(par[i+1]) && isanumber(par[i+2]))
2684 {
2685 xcur = atola(par[i+1], 0);
2686 ycur = atola(par[i+2], 0);
2687 i += 2;
2688 pointgiven++;
2689 }
2690 } else if (namesamen(pt, x_("delete-point"), l) == 0 && l >= 1)
2691 {
2692 deletepoint++;
2693 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2694 if (store == NONODEINST) return;
2695 high = us_getonehighlight();
2696 whichpoint = high->frompoint;
2697 } else if (namesamen(pt, x_("next-point"), l) == 0 && l >= 1)
2698 {
2699 nextpoint++;
2700 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2701 if (store == NONODEINST) return;
2702 high = us_getonehighlight();
2703 whichpoint = high->frompoint;
2704 } else if (namesamen(pt, x_("prev-point"), l) == 0 && l >= 2)
2705 {
2706 prevpoint++;
2707 store = (NODEINST *)us_getobject(VNODEINST, FALSE);
2708 if (store == NONODEINST) return;
2709 high = us_getonehighlight();
2710 whichpoint = high->frompoint;
2711 } else if (namesamen(pt, x_("wait-for-down"), l) == 0 && l >= 1)
2712 {
2713 waitfordown = TRUE;
2714 } else
2715 {
2716 ttyputbadusage(x_("node trace"));
2717 return;
2718 }
2719 }
2720
2721 if (addpoint + deletepoint + movepoint + nextpoint + prevpoint > 1)
2722 {
2723 us_abortcommand(_("Can only add OR delete OR move OR change point"));
2724 return;
2725 }
2726
2727 /* make sure node can handle trace information */
2728 if (store != NONODEINST)
2729 {
2730 if ((store->proto->userbits&HOLDSTRACE) == 0)
2731 {
2732 us_abortcommand(_("Sorry, %s nodes cannot hold outline information"),
2733 describenodeproto(store->proto));
2734 return;
2735 }
2736 }
2737
2738 /* handle moving around the trace */
2739 if (nextpoint != 0)
2740 {
2741 var = gettrace(store);
2742 if (var == NOVARIABLE)
2743 {
2744 us_abortcommand(_("No points on this node"));
2745 return;
2746 }
2747 size = getlength(var) / 2;
2748 whichpoint++;
2749 if (whichpoint >= size) whichpoint = 0;
2750
2751 us_clearhighlightcount();
2752 newhigh.status = HIGHFROM;
2753 newhigh.fromgeom = store->geom;
2754 newhigh.fromport = NOPORTPROTO;
2755 newhigh.frompoint = whichpoint;
2756 newhigh.cell = store->parent;
2757 us_addhighlight(&newhigh);
2758 return;
2759 }
2760 if (prevpoint != 0)
2761 {
2762 var = gettrace(store);
2763 if (var == NOVARIABLE)
2764 {
2765 us_abortcommand(_("No points on this node"));
2766 return;
2767 }
2768 size = getlength(var) / 2;
2769 whichpoint--;
2770 if (whichpoint < 0) whichpoint = size-1;
2771
2772 us_clearhighlightcount();
2773 newhigh.status = HIGHFROM;
2774 newhigh.fromgeom = store->geom;
2775 newhigh.fromport = NOPORTPROTO;
2776 newhigh.frompoint = whichpoint;
2777 newhigh.cell = store->parent;
2778 us_addhighlight(&newhigh);
2779 return;
2780 }
2781
2782 /* handle freeform cursor traces */
2783 if (addpoint == 0 && deletepoint == 0 && movepoint == 0)
2784 {
2785 /* just do tracking if no storage requested */
2786 if (store == NONODEINST)
2787 {
2788 /* save highlighting */
2789 us_pushhighlight();
2790 us_clearhighlightcount();
2791
2792 trackcursor(waitfordown, us_ignoreup, us_tracebegin,
2793 us_tracedown, us_stoponchar, us_traceup, TRACKDRAWING);
2794
2795 /* restore highlighting */
2796 us_pophighlight(FALSE);
2797 return;
2798 }
2799
2800 /* clear highlighting */
2801 us_clearhighlightcount();
2802
2803 /* get the trace */
2804 trackcursor(waitfordown, us_ignoreup, us_tracebegin, us_tracedown,
2805 us_stoponchar, us_traceup, TRACKDRAWING);
2806 if (el_pleasestop != 0) return;
2807
2808 /* get the trace data in the "%T" variable */
2809 var = getval((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_commandvarname('T'));
2810 if (var == NOVARIABLE)
2811 {
2812 us_abortcommand(_("Invalid outline information"));
2813 return;
2814 }
2815 size = getlength(var) / 2;
2816
2817 /* create a place to keep this data */
2818 newlist = emalloc((size*2*SIZEOFINTBIG), el_tempcluster);
2819 if (newlist == 0)
2820 {
2821 ttyputnomemory();
2822 return;
2823 }
2824
2825 /* copy the trace from "%T" to "newlist" */
2826 curlamb = el_curlib->lambda[el_curtech->techindex];
2827 el_curlib->lambda[el_curtech->techindex] = 4;
2828 nogood = 0;
2829 for(i=0; i<size; i++)
2830 {
2831 x = ((INTBIG *)var->addr)[i*2];
2832 y = ((INTBIG *)var->addr)[i*2+1];
2833 if (us_setxy(x, y)) nogood++;
2834 (void)getxy(&xcur, &ycur);
2835 newlist[i*2] = xcur; newlist[i*2+1] = ycur;
2836 }
2837 el_curlib->lambda[el_curtech->techindex] = curlamb;
2838
2839 /* if data is valid, store it in the node */
2840 if (nogood != 0) ttyputerr(_("Outline not inside window")); else
2841 {
2842 us_settrace(store, newlist, size);
2843
2844 /* highlighting the node */
2845 newhigh.status = HIGHFROM;
2846 newhigh.fromgeom = store->geom;
2847 newhigh.fromport = NOPORTPROTO;
2848 newhigh.frompoint = size+1;
2849 newhigh.cell = store->parent;
2850 us_addhighlight(&newhigh);
2851 }
2852 efree((CHAR *)newlist);
2853 return;
2854 }
2855
2856 /* add a point to a trace on this object */
2857 if (addpoint != 0)
2858 {
2859 /* clear highlighting */
2860 us_clearhighlightcount();
2861
2862 stillok = TRUE;
2863 if (pointgiven == 0)
2864 {
2865 if (us_demandxy(&xcur, &ycur)) stillok = FALSE; else
2866 {
2867 gridalign(&xcur, &ycur, 1, np);
2868
2869 /* adjust the cursor position if selecting interactively */
2870 if ((us_tool->toolstate&INTERACTIVE) != 0)
2871 {
2872 us_pointinit(store, whichpoint);
2873 trackcursor(FALSE, us_ignoreup, us_pointbegin, us_addpdown,
2874 us_stoponchar, us_dragup, TRACKDRAGGING);
2875 if (el_pleasestop != 0) stillok = FALSE; else
2876 {
2877 if (us_demandxy(&xcur, &ycur)) stillok = FALSE; else
2878 gridalign(&xcur, &ycur, 1, np);
2879 }
2880 }
2881 }
2882 }
2883
2884 if (stillok)
2885 {
2886 var = gettrace(store);
2887 if (var == NOVARIABLE)
2888 {
2889 d[0] = xcur; d[1] = ycur;
2890 us_settrace(store, d, 1);
2891 whichpoint = 1;
2892 } else
2893 {
2894 size = getlength(var) / 2;
2895 newlist = emalloc(((size+1)*2*SIZEOFINTBIG), el_tempcluster);
2896 if (newlist == 0)
2897 {
2898 ttyputnomemory();
2899 return;
2900 }
2901 p = 0;
2902 makerot(store, trans);
2903 x = (store->highx + store->lowx) / 2;
2904 y = (store->highy + store->lowy) / 2;
2905 if (whichpoint == 0) whichpoint++;
2906 for(i=0; i<size; i++)
2907 {
2908 xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y, &newlist[p],
2909 &newlist[p+1], trans);
2910 p += 2;
2911 if (i+1 == whichpoint)
2912 {
2913 newlist[p++] = xcur;
2914 newlist[p++] = ycur;
2915 }
2916 }
2917
2918 /* now re-draw this trace */
2919 us_settrace(store, newlist, size+1);
2920 whichpoint++;
2921 efree((CHAR *)newlist);
2922 }
2923 }
2924
2925 /* highlighting the node */
2926 newhigh.status = HIGHFROM;
2927 newhigh.fromgeom = store->geom;
2928 newhigh.fromport = NOPORTPROTO;
2929 newhigh.frompoint = whichpoint;
2930 newhigh.cell = store->parent;
2931 us_addhighlight(&newhigh);
2932 return;
2933 }
2934
2935 /* delete the current point */
2936 if (deletepoint != 0)
2937 {
2938 var = gettrace(store);
2939 if (var == NOVARIABLE)
2940 {
2941 us_abortcommand(_("No outline data to delete"));
2942 return;
2943 }
2944 if (whichpoint == 0)
2945 {
2946 us_abortcommand(_("Highlight a point or line to delete"));
2947 return;
2948 }
2949 size = getlength(var) / 2;
2950 if (size <= 1)
2951 {
2952 us_abortcommand(_("Outline must retain at least one point"));
2953 return;
2954 }
2955 newlist = emalloc(((size-1)*2*SIZEOFINTBIG), el_tempcluster);
2956 if (newlist == 0)
2957 {
2958 ttyputnomemory();
2959 return;
2960 }
2961 p = 0;
2962 makerot(store, trans);
2963 x = (store->highx + store->lowx) / 2;
2964 y = (store->highy + store->lowy) / 2;
2965 total = 0;
2966 for(i=0; i<size; i++)
2967 {
2968 if (i+1 == whichpoint) { total++; continue;}
2969 xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y,
2970 &newlist[p], &newlist[p+1], trans);
2971 p += 2;
2972 }
2973
2974 /* clear highlighting */
2975 us_clearhighlightcount();
2976
2977 /* now re-draw this trace */
2978 us_settrace(store, newlist, size-total);
2979 whichpoint = maxi(whichpoint-total, 1);
2980 efree((CHAR *)newlist);
2981
2982 /* highlighting the node */
2983 newhigh.status = HIGHFROM;
2984 newhigh.fromgeom = store->geom;
2985 newhigh.fromport = NOPORTPROTO;
2986 newhigh.frompoint = whichpoint;
2987 newhigh.cell = store->parent;
2988 us_addhighlight(&newhigh);
2989 return;
2990 }
2991
2992 /* move a point on a trace on this object */
2993 if (movepoint != 0)
2994 {
2995 var = gettrace(store);
2996 if (var == NOVARIABLE)
2997 {
2998 us_abortcommand(_("No outline data to move"));
2999 return;
3000 }
3001 if (whichpoint == 0)
3002 {
3003 us_abortcommand(_("Highlight a point or line to move"));
3004 return;
3005 }
3006
3007 /* save highlighting */
3008 us_pushhighlight();
3009 us_clearhighlightcount();
3010
3011 stillok = TRUE;
3012 if (pointgiven == 0)
3013 {
3014 if (us_demandxy(&xcur, &ycur)) stillok = FALSE; else
3015 {
3016 gridalign(&xcur, &ycur, 1, np);
3017
3018 /* adjust the cursor position if selecting interactively */
3019 if ((us_tool->toolstate&INTERACTIVE) != 0)
3020 {
3021 us_pointinit(store, whichpoint);
3022 trackcursor(FALSE, us_ignoreup, us_pointbegin, us_movepdown,
3023 us_stopandpoponchar, us_dragup, TRACKDRAGGING);
3024 if (el_pleasestop != 0) stillok = FALSE; else
3025 {
3026 if (us_demandxy(&xcur, &ycur)) stillok = FALSE; else
3027 gridalign(&xcur, &ycur, 1, np);
3028 }
3029 }
3030 }
3031 }
3032
3033 if (stillok)
3034 {
3035 size = getlength(var) / 2;
3036 newlist = emalloc((size*2*SIZEOFINTBIG), el_tempcluster);
3037 if (newlist == 0)
3038 {
3039 ttyputnomemory();
3040 us_pophighlight(FALSE);
3041 return;
3042 }
3043 makerot(store, trans);
3044 x = (store->highx + store->lowx) / 2;
3045 y = (store->highy + store->lowy) / 2;
3046 for(i=0; i<size; i++)
3047 {
3048 if (i+1 == whichpoint)
3049 {
3050 newlist[i*2] = xcur;
3051 newlist[i*2+1] = ycur;
3052 } else xform(((INTBIG *)var->addr)[i*2]+x, ((INTBIG *)var->addr)[i*2+1]+y,
3053 &newlist[i*2], &newlist[i*2+1], trans);
3054 }
3055
3056 /* now re-draw this trace */
3057 us_settrace(store, newlist, size);
3058 efree((CHAR *)newlist);
3059 }
3060
3061 /* restore highlighting */
3062 us_pophighlight(TRUE);
3063 return;
3064 }
3065 return;
3066 }
3067
3068 ttyputbadusage(x_("node"));
3069 }
3070