1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrstatus.c
6 * User interface tool: status display routines
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 "drc.h"
36 #include "network.h"
37 #include "efunction.h"
38 #include "edialogs.h"
39 #include "tecgen.h"
40 #include "tecschem.h"
41 #include "usrdiacom.h"
42
43 static INTBIG *us_layer_letter_data = 0; /* cache for "us_layerletters" */
44 static BOOLEAN us_shadowarcdetails = FALSE; /* true if the arc status field has details */
45
46 /* working memory for "us_uniqueportname()" */
47 static CHAR *us_uniqueretstr = NOSTRING;
48
49 /* working memory for "us_shadowarcproto()" */
50 static CHAR *us_lastnetworkname;
51 static INTBIG us_lastnetworknametotal = 0;
52
53 /* structure for "usrbits" information parsing */
54 struct explanation
55 {
56 INTBIG bit; /* bit mask in word */
57 INTBIG shift; /* shift of bit mask (-1 if a flag) */
58 CHAR *name; /* name of the field */
59 };
60
61 /* prototypes for local routines */
62 static void us_addobjects(NODEPROTO*);
63 static BOOLEAN us_wildmatch(CHAR*, CHAR*);
64 static void us_explaintool(INTBIG, struct explanation[]);
65 static void us_drawarcmenu(ARCPROTO *ap);
66 static BOOLEAN us_isuniquename(CHAR *name, NODEPROTO *cell, INTBIG type, void *exclude);
67
68 static STATUSFIELD *us_clearstatuslines[3] = {0, 0, 0};
69
70 /*
71 * Routine to free all memory associated with this module.
72 */
us_freestatusmemory(void)73 void us_freestatusmemory(void)
74 {
75 REGISTER INTBIG i, lines;
76
77 if (us_layer_letter_data != 0) efree((CHAR *)us_layer_letter_data);
78 if (us_statusalign != 0) ttyfreestatusfield(us_statusalign);
79 if (us_statusangle != 0) ttyfreestatusfield(us_statusangle);
80 if (us_statusarc != 0) ttyfreestatusfield(us_statusarc);
81 if (us_statuscell != 0) ttyfreestatusfield(us_statuscell);
82 if (us_statuscellsize != 0) ttyfreestatusfield(us_statuscellsize);
83 if (us_statusselectcount != 0) ttyfreestatusfield(us_statusselectcount);
84 if (us_statusgridsize != 0) ttyfreestatusfield(us_statusgridsize);
85 if (us_statuslambda != 0) ttyfreestatusfield(us_statuslambda);
86 if (us_statusnode != 0) ttyfreestatusfield(us_statusnode);
87 if (us_statustechnology != 0) ttyfreestatusfield(us_statustechnology);
88 if (us_statusxpos != 0) ttyfreestatusfield(us_statusxpos);
89 if (us_statusypos != 0) ttyfreestatusfield(us_statusypos);
90 if (us_statusproject != 0) ttyfreestatusfield(us_statusproject);
91 if (us_statusroot != 0) ttyfreestatusfield(us_statusroot);
92 if (us_statuspart != 0) ttyfreestatusfield(us_statuspart);
93 if (us_statuspackage != 0) ttyfreestatusfield(us_statuspackage);
94 if (us_statusselection != 0) ttyfreestatusfield(us_statusselection);
95
96 lines = ttynumstatuslines();
97 for(i=0; i<lines; i++) ttyfreestatusfield(us_clearstatuslines[i]);
98
99 if (us_uniqueretstr != NOSTRING) efree(us_uniqueretstr);
100 if (us_lastnetworknametotal > 0) efree((CHAR *)us_lastnetworkname);
101 }
102
103 /******************** STATUS DISPLAY MANIPULATION ********************/
104
105 /* routine to determine the state of the status fields */
us_initstatus(void)106 void us_initstatus(void)
107 {
108 REGISTER INTBIG lines, i;
109 static BOOLEAN first = TRUE;
110
111 if (first)
112 {
113 first = FALSE;
114 lines = ttynumstatuslines();
115 for(i=0; i<lines; i++) us_clearstatuslines[i] = ttydeclarestatusfield(i+1, 0, 100, x_(""));
116 us_statuscell = us_statusnode = us_statusarc = 0;
117 us_statuslambda = us_statustechnology = us_statusxpos = us_statusypos = 0;
118 us_statusangle = us_statusalign = us_statuscellsize = us_statusgridsize = 0;
119 us_statusproject = us_statusroot = us_statuspart = us_statuspackage = 0;
120 us_statusselection = us_statusselectcount = 0;
121 us_statuscell = ttydeclarestatusfield(0, 0, 0, x_(""));
122 us_statusnode = ttydeclarestatusfield(1, 0, 20, _("NODE: "));
123 us_statusarc = ttydeclarestatusfield(1, 20, 40, _("ARC: "));
124 us_statusselectcount = ttydeclarestatusfield(1, 40, 52, _("SELECTED: "));
125 us_statuscellsize = ttydeclarestatusfield(1, 52, 69, _("SIZE: "));
126 us_statuslambda = ttydeclarestatusfield(1, 69, 82, _("LAMBDA: "));
127 us_statustechnology = ttydeclarestatusfield(1, 82, 100, _("TECHNOLOGY: "));
128 us_statusxpos = ttydeclarestatusfield(1, 69, 82, _("X: "));
129 us_statusypos = ttydeclarestatusfield(1, 82, 100, _("Y: "));
130 if (lines > 1)
131 {
132 us_statusangle = ttydeclarestatusfield(2, 0, 25, _("ANGLE: "));
133 us_statusalign = ttydeclarestatusfield(2, 25, 50, _("ALIGN: "));
134 us_statusgridsize = ttydeclarestatusfield(2, 75, 100, _("GRID: "));
135 }
136 }
137 }
138
139 /*
140 * Routine to create a field in the status display. "line" is the status line number (line 0
141 * is the window header). "startper" and "endper" are the starting and ending percentages
142 * of the line to use (ignored for the window header). "label" is the prefix to use.
143 * Returns an object to use with subsequent calls to "ttysetstatusfield" (zero on error).
144 */
ttydeclarestatusfield(INTBIG line,INTBIG startper,INTBIG endper,CHAR * label)145 STATUSFIELD *ttydeclarestatusfield(INTBIG line, INTBIG startper, INTBIG endper, CHAR *label)
146 {
147 STATUSFIELD *sf;
148
149 sf = (STATUSFIELD *)emalloc((sizeof (STATUSFIELD)), us_tool->cluster);
150 if (sf == 0) return(0);
151 if (line < 0 || line > ttynumstatuslines()) return(0);
152 if (line > 0 && (startper < 0 || endper > 100 || startper >= endper)) return(0);
153 sf->line = line;
154 sf->startper = startper;
155 sf->endper = endper;
156 (void)allocstring(&sf->label, label, us_tool->cluster);
157 #ifdef USEQT
158 ttysetstatusfield(NOWINDOWFRAME, sf, x_(""), FALSE);
159 #endif
160 return(sf);
161 }
162
163 /* write the current grid alignment from "us_alignment_ratio" */
us_setalignment(WINDOWFRAME * frame)164 void us_setalignment(WINDOWFRAME *frame)
165 {
166 CHAR valstring[60];
167
168 (void)estrcpy(valstring, frtoa(us_alignment_ratio));
169 if (us_edgealignment_ratio != 0)
170 {
171 (void)estrcat(valstring, x_("/"));
172 (void)estrcat(valstring, frtoa(us_edgealignment_ratio));
173 }
174 ttysetstatusfield(frame, us_statusalign, valstring, FALSE);
175 }
176
177 /* write the current lambda value from the current library/technology in microns */
us_setlambda(WINDOWFRAME * frame)178 void us_setlambda(WINDOWFRAME *frame)
179 {
180 REGISTER INTBIG len;
181 float lambdainmicrons;
182 CHAR hold[50];
183
184 /* show nothing in X/Y mode */
185 if ((us_tool->toolstate&SHOWXY) != 0) return;
186
187 lambdainmicrons = scaletodispunit(el_curlib->lambda[el_curtech->techindex], DISPUNITMIC);
188 (void)esnprintf(hold, 50, x_("%g"), lambdainmicrons);
189 for(;;)
190 {
191 len = estrlen(hold)-1;
192 if (hold[len] != '0') break;
193 hold[len] = 0;
194 }
195 if (hold[len] == '.') hold[len] = 0;
196 (void)estrcat(hold, x_("u"));
197 ttysetstatusfield(NOWINDOWFRAME, us_statuslambda, hold, FALSE);
198 }
199
200 /* write the name of the current technology from "el_curtech->techname" */
us_settechname(WINDOWFRAME * frame)201 void us_settechname(WINDOWFRAME *frame)
202 {
203 /* show nothing in XY mode */
204 if ((us_tool->toolstate&SHOWXY) != 0) return;
205
206 ttysetstatusfield(NOWINDOWFRAME, us_statustechnology, el_curtech->techname, TRUE);
207 }
208
209 /* write the cursor coordinates */
us_setcursorpos(WINDOWFRAME * frame,INTBIG x,INTBIG y)210 void us_setcursorpos(WINDOWFRAME *frame, INTBIG x, INTBIG y)
211 {
212 static INTBIG lastx=0, lasty=0;
213
214 /* show nothing in non XY mode */
215 if ((us_tool->toolstate&SHOWXY) == 0) return;
216
217 if (lastx != x)
218 {
219 ttysetstatusfield(frame, us_statusxpos, latoa(x, 0), FALSE);
220 lastx = x;
221 }
222
223 if (lasty != y)
224 {
225 ttysetstatusfield(frame, us_statusypos, latoa(y, 0), FALSE);
226 lasty = y;
227 }
228 }
229
230 /* set the current nodeproto */
us_setnodeproto(NODEPROTO * np)231 void us_setnodeproto(NODEPROTO *np)
232 {
233 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_node_key, (INTBIG)np, VNODEPROTO|VDONTSAVE);
234 }
235
236 /*
237 * set the current arcproto to "ap". If "always" is false, do this only if sensible.
238 */
us_setarcproto(ARCPROTO * ap,BOOLEAN always)239 void us_setarcproto(ARCPROTO *ap, BOOLEAN always)
240 {
241 /* don't do it if setting universal arc when not in generic technology */
242 if (!always && ap != NOARCPROTO && ap->tech != el_curtech)
243 {
244 if (ap == gen_universalarc) return;
245 }
246 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_arc_key, (INTBIG)ap, VARCPROTO|VDONTSAVE);
247 }
248
249 /* shadow changes to the current nodeproto */
us_shadownodeproto(WINDOWFRAME * frame,NODEPROTO * np)250 void us_shadownodeproto(WINDOWFRAME *frame, NODEPROTO *np)
251 {
252 REGISTER CHAR *pt;
253 HIGHLIGHT high;
254 REGISTER VARIABLE *var;
255 REGISTER INTBIG len;
256 REGISTER NODEINST *ni;
257 REGISTER void *infstr;
258
259 /* code cannot be called by multiple procesors: uses globals */
260 NOT_REENTRANT;
261
262 us_curnodeproto = np;
263
264 if (np == NONODEPROTO) pt = x_(""); else
265 pt = describenodeproto(np);
266
267 /* see if the selection further qualifies the node description */
268 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
269 if (var != NOVARIABLE)
270 {
271 len = getlength(var);
272 if (len == 1)
273 {
274 if (!us_makehighlight(((CHAR **)var->addr)[0], &high))
275 {
276 if ((high.status&HIGHTEXT) != 0)
277 {
278 infstr = initinfstr();
279 var = high.fromvar;
280 if (var == NOVARIABLE)
281 {
282 if (high.fromport == NOPORTPROTO)
283 {
284 formatinfstr(infstr, _("%s (cell name)"),
285 describenodeinst(high.fromgeom->entryaddr.ni));
286 } else
287 {
288 formatinfstr(infstr, _("%s (export)"), high.fromport->protoname);
289 }
290 } else
291 {
292 if (high.fromgeom == NOGEOM)
293 {
294 formatinfstr(infstr, _("%s on cell"),
295 us_trueattributename(var));
296 } else if (high.fromport != NOPORTPROTO)
297 {
298 formatinfstr(infstr, _("%s on export"),
299 us_trueattributename(var));
300 } else
301 {
302 if (high.fromgeom->entryisnode)
303 {
304 ni = high.fromgeom->entryaddr.ni;
305 if (ni->proto == gen_invispinprim)
306 {
307 addstringtoinfstr(infstr, us_invisiblepintextname(var));
308 } else
309 {
310 formatinfstr(infstr, _("%s on node"), us_trueattributename(var));
311 }
312 } else
313 {
314 formatinfstr(infstr, _("%s on arc"), us_trueattributename(var));
315 }
316 }
317 }
318 pt = returninfstr(infstr);
319 } else if ((high.status&HIGHFROM) != 0 && high.fromgeom->entryisnode)
320 {
321 ni = high.fromgeom->entryaddr.ni;
322 if (ni->proto == np)
323 {
324 /* one node selected that is the same as the current proto: qualify proto */
325 infstr = initinfstr();
326 addstringtoinfstr(infstr, us_describenodeinsttype(np, ni, ni->userbits&NTECHBITS));
327 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
328 if (var != NOVARIABLE)
329 formatinfstr(infstr, x_(" [%s]"), (CHAR *)var->addr);
330 pt = returninfstr(infstr);
331 }
332 }
333 }
334 }
335 }
336 ttysetstatusfield(frame, us_statusnode, pt, TRUE);
337
338 /* if a node was described with details, clear them */
339 if (us_shadowarcdetails) us_shadowarcproto(frame, us_curarcproto);
340
341 /* highlight the menu entry */
342 us_showcurrentnodeproto();
343 }
344
345 /*
346 * routine to draw highlighting around the menu entry with the current
347 * node prototype
348 */
us_showcurrentnodeproto(void)349 void us_showcurrentnodeproto(void)
350 {
351 REGISTER CHAR *str;
352 REGISTER INTBIG x, y;
353 REGISTER VARIABLE *var;
354 REGISTER NODEPROTO *np;
355 COMMANDBINDING commandbinding;
356
357 if (us_curnodeproto == NONODEPROTO) return;
358 if ((us_tool->toolstate&MENUON) == 0) return;
359 if ((us_tool->toolstate&ONESHOTMENU) != 0) return;
360 if (us_menuhnx >= 0) us_highlightmenu(us_menuhnx, us_menuhny, el_colmenbor);
361 us_menuhnx = -1;
362 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
363 if (var != NOVARIABLE) for(x=0; x<us_menux; x++) for(y=0; y<us_menuy; y++)
364 {
365 if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
366 str = ((CHAR **)var->addr)[x * us_menuy + y];
367 us_parsebinding(str, &commandbinding);
368 np = commandbinding.nodeglyph;
369 us_freebindingparse(&commandbinding);
370 if (np == us_curnodeproto)
371 {
372 us_menuhnx = x; us_menuhny = y;
373 us_highlightmenu(us_menuhnx, us_menuhny, el_colhmenbor);
374 break;
375 }
376 }
377 }
378
379 /* shadow changes to the current arcproto */
us_shadowarcproto(WINDOWFRAME * frame,ARCPROTO * ap)380 void us_shadowarcproto(WINDOWFRAME *frame, ARCPROTO *ap)
381 {
382 REGISTER ARCPROTO *oldap;
383 REGISTER NETWORK *net, **netlist;
384 REGISTER CHAR *pt;
385 REGISTER INTBIG len;
386 REGISTER void *infstr;
387
388 /* first show the arc/network in the status bar */
389 netlist = net_gethighlightednets(FALSE);
390 net = netlist[0];
391 if (net == NONETWORK || (net->globalnet < 0 && net->namecount <= 0))
392 {
393 pt = x_("");
394 us_shadowarcdetails = FALSE;
395 } else
396 {
397 pt = describenetwork(net);
398 us_shadowarcdetails = TRUE;
399 }
400 if (ap != us_curarcproto || us_lastnetworkname == 0 || namesame(us_lastnetworkname, pt) != 0)
401 {
402 len = estrlen(pt) + 1;
403 if (len > us_lastnetworknametotal)
404 {
405 if (us_lastnetworknametotal > 0) efree((CHAR *)us_lastnetworkname);
406 us_lastnetworknametotal = 0;
407 us_lastnetworkname = (CHAR *)emalloc(len * SIZEOFCHAR, us_tool->cluster);
408 if (us_lastnetworkname == 0) return;
409 us_lastnetworknametotal = len;
410 }
411 estrcpy(us_lastnetworkname, pt);
412 pt = describearcproto(ap);
413 if (*us_lastnetworkname != 0)
414 {
415 infstr = initinfstr();
416 formatinfstr(infstr, x_("%s [%s]"), pt, us_lastnetworkname);
417 pt = returninfstr(infstr);
418 }
419
420 ttysetstatusfield(frame, us_statusarc, pt, TRUE);
421 }
422
423 /* next handle menu highlighting */
424 if (us_curarcproto != ap)
425 {
426 /* undraw the menu entry with the last arc proto in it */
427 oldap = us_curarcproto;
428 us_curarcproto = ap;
429
430 /* adjust the component menu entries */
431 if (oldap != NOARCPROTO) us_drawarcmenu(oldap);
432 if (us_curarcproto != NOARCPROTO) us_drawarcmenu(us_curarcproto);
433 us_showcurrentarcproto();
434 }
435 }
436
437 /*
438 * Routine to find arcproto "ap" in the component menu and redraw that entry.
439 */
us_drawarcmenu(ARCPROTO * ap)440 void us_drawarcmenu(ARCPROTO *ap)
441 {
442 REGISTER CHAR *str;
443 REGISTER INTBIG x, y;
444 REGISTER VARIABLE *var;
445 REGISTER ARCPROTO *pap;
446 COMMANDBINDING commandbinding;
447
448 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
449 if (var == NOVARIABLE) return;
450 for(x=0; x<us_menux; x++)
451 for(y=0; y<us_menuy; y++)
452 {
453 if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
454 str = ((CHAR **)var->addr)[x * us_menuy + y];
455 us_parsebinding(str, &commandbinding);
456 pap = commandbinding.arcglyph;
457 us_freebindingparse(&commandbinding);
458 if (pap == ap)
459 {
460 us_drawmenuentry(x, y, str);
461 return;
462 }
463 }
464 }
465
466 /*
467 * routine to draw highlighting around the menu entry with the current
468 * arc prototype
469 */
us_showcurrentarcproto(void)470 void us_showcurrentarcproto(void)
471 {
472 REGISTER CHAR *str;
473 REGISTER INTBIG x, y;
474 REGISTER VARIABLE *var;
475 REGISTER ARCPROTO *ap;
476 COMMANDBINDING commandbinding;
477
478 /* highlight the menu entry */
479 if (us_curarcproto == NOARCPROTO) return;
480 if ((us_tool->toolstate&MENUON) == 0) return;
481 if ((us_tool->toolstate&ONESHOTMENU) != 0) return;
482 if (us_menuhax >= 0) us_highlightmenu(us_menuhax, us_menuhay, el_colmenbor);
483 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_binding_menu_key);
484 if (var != NOVARIABLE) for(x=0; x<us_menux; x++) for(y=0; y<us_menuy; y++)
485 {
486 if (us_menupos <= 1) str = ((CHAR **)var->addr)[y * us_menux + x]; else
487 str = ((CHAR **)var->addr)[x * us_menuy + y];
488 us_parsebinding(str, &commandbinding);
489 ap = commandbinding.arcglyph;
490 us_freebindingparse(&commandbinding);
491 if (ap == us_curarcproto)
492 {
493 us_menuhax = x; us_menuhay = y;
494 us_highlightmenu(us_menuhax, us_menuhay, el_colhmenbor);
495 break;
496 }
497 }
498 }
499
500 /* write the default placement angle from "tool:user.USER_placement_angle" */
us_setnodeangle(WINDOWFRAME * frame)501 void us_setnodeangle(WINDOWFRAME *frame)
502 {
503 CHAR hold[5];
504 REGISTER VARIABLE *var;
505 REGISTER INTBIG pangle;
506
507 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_placement_angle_key);
508 if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
509 (void)estrcpy(hold, frtoa(pangle%3600*WHOLE/10));
510 if (pangle >= 3600) (void)estrcat(hold, x_("T"));
511 ttysetstatusfield(frame, us_statusangle, hold, FALSE);
512 }
513
514 /* write the name of the cell in window "w" */
us_setcellname(WINDOWPART * w)515 void us_setcellname(WINDOWPART *w)
516 {
517 REGISTER EDITOR *ed;
518 REGISTER void *infstr;
519
520 /* do not show name of explorer window when it is split */
521 if ((w->state&WINDOWTYPE) == EXPLORERWINDOW &&
522 estrcmp(w->location, x_("entire")) != 0) return;
523
524 /* if this is part of a frame and the current window is in another part, don't write name */
525 if (el_curwindowpart != NOWINDOWPART && w != el_curwindowpart &&
526 w->frame == el_curwindowpart->frame) return;
527
528 /* write the cell name */
529 infstr = initinfstr();
530 switch (w->state&WINDOWTYPE)
531 {
532 case TEXTWINDOW:
533 case POPTEXTWINDOW:
534 if (w->curnodeproto == NONODEPROTO)
535 {
536 ed = w->editor;
537 if (ed != NOEDITOR)
538 {
539 addstringtoinfstr(infstr, ed->header);
540 break;
541 }
542 }
543 /* FALLTHROUGH */
544 case DISPWINDOW:
545 case DISP3DWINDOW:
546 if (w->curnodeproto != NONODEPROTO)
547 {
548 formatinfstr(infstr, x_("%s:%s"), w->curnodeproto->lib->libname,
549 nldescribenodeproto(w->curnodeproto));
550 if (w->curnodeproto->lib != el_curlib)
551 formatinfstr(infstr, _(" - Current library: %s"), el_curlib->libname);
552 }
553 break;
554 case EXPLORERWINDOW:
555 addstringtoinfstr(infstr, _("Cell Explorer"));
556 break;
557 case WAVEFORMWINDOW:
558 if (w->curnodeproto != NONODEPROTO)
559 {
560 formatinfstr(infstr, _("Waveform of %s"), describenodeproto(w->curnodeproto));
561 } else
562 {
563 addstringtoinfstr(infstr, _("Waveform"));
564 }
565 break;
566 }
567
568 ttysetstatusfield(w->frame, us_statuscell, returninfstr(infstr), TRUE);
569 }
570
571 /*
572 * Routine to update the number of selected objects.
573 */
us_setselectioncount(void)574 void us_setselectioncount(void)
575 {
576 CHAR valstring[50];
577 REGISTER VARIABLE *var;
578 REGISTER WINDOWPART *w;
579
580 valstring[0] = 0;
581 var = getvalkey((INTBIG)us_tool, VTOOL, VSTRING|VISARRAY, us_highlightedkey);
582 if (var != NOVARIABLE)
583 esnprintf(valstring, 50, x_("%ld"), getlength(var));
584
585 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
586 {
587 if ((w->state&WINDOWTYPE) == DISPWINDOW)
588 ttysetstatusfield(w->frame, us_statusselectcount, valstring, FALSE); else
589 ttysetstatusfield(w->frame, us_statusselectcount, x_(""), FALSE);
590 }
591 }
592
593 /*
594 * write the size of the cell in window "w" from the size of "w->curnodeproto"
595 */
us_setcellsize(WINDOWPART * w)596 void us_setcellsize(WINDOWPART *w)
597 {
598 REGISTER NODEPROTO *np;
599 CHAR valstring[50];
600 REGISTER INTBIG lines, lambda;
601
602 np = w->curnodeproto;
603 valstring[0] = 0;
604 if (np != NONODEPROTO)
605 {
606 switch (w->state&WINDOWTYPE)
607 {
608 case TEXTWINDOW:
609 case POPTEXTWINDOW:
610 lines = us_totallines(w);
611 esnprintf(valstring, 50, _("%ld lines"), lines);
612 break;
613 case DISPWINDOW:
614 case DISP3DWINDOW:
615 lambda = lambdaofcell(np);
616 (void)estrcpy(valstring, latoa(np->highx - np->lowx, lambda));
617 (void)estrcat(valstring, x_("x"));
618 (void)estrcat(valstring, latoa(np->highy - np->lowy, lambda));
619 break;
620 }
621 }
622 ttysetstatusfield(w->frame, us_statuscellsize, valstring, FALSE);
623 }
624
625 /* write the grid size of window "w" from "w->gridx" and "w->gridy" */
us_setgridsize(WINDOWPART * w)626 void us_setgridsize(WINDOWPART *w)
627 {
628 REGISTER NODEPROTO *np;
629 CHAR valstring[50];
630
631 np = w->curnodeproto;
632 valstring[0] = 0;
633 if (np != NONODEPROTO)
634 {
635 switch (w->state&WINDOWTYPE)
636 {
637 case DISPWINDOW:
638 case DISP3DWINDOW:
639 (void)estrcpy(valstring, frtoa(w->gridx));
640 (void)estrcat(valstring, x_("x"));
641 (void)estrcat(valstring, frtoa(w->gridy));
642 break;
643 }
644 }
645 ttysetstatusfield(NOWINDOWFRAME, us_statusgridsize, valstring, FALSE);
646 }
647
648 /* routine to re-write the status information (on all frames if frame is 0) */
us_redostatus(WINDOWFRAME * frame)649 void us_redostatus(WINDOWFRAME *frame)
650 {
651 REGISTER WINDOWPART *w;
652 REGISTER ARCPROTO *ap;
653 REGISTER NODEPROTO *np;
654 REGISTER INTBIG lines, i;
655
656 /* clear the status bar */
657 lines = ttynumstatuslines();
658 for(i=0; i<lines; i++) ttysetstatusfield(NOWINDOWFRAME, us_clearstatuslines[i], x_(""), FALSE);
659
660 /* node and arc */
661 ap = us_curarcproto; np = us_curnodeproto;
662 us_curarcproto = (ARCPROTO *)0; us_curnodeproto = (NODEPROTO *)0;
663 us_shadownodeproto(NOWINDOWFRAME, np);
664 us_shadowarcproto(NOWINDOWFRAME, ap);
665
666 /* write the window information on the window lines */
667 for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
668 {
669 us_setcellname(w);
670 if (graphicshas(CANSTATUSPERFRAME) || w->frame == frame)
671 us_setcellsize(w);
672 us_setgridsize(w);
673 }
674 if (el_curwindowpart != NOWINDOWPART)
675 us_setcellsize(el_curwindowpart);
676
677 /* other fields */
678 us_setnodeangle(frame);
679 us_setalignment(frame);
680 us_setlambda(frame);
681 us_settechname(frame);
682 us_setselectioncount();
683 }
684
685 /******************** OUTPUT PREPARATION ********************/
686
687 /*
688 * routine to list macros by the package of origin
689 */
us_printmacros(void)690 void us_printmacros(void)
691 {
692 INTBIG len, coms, keyboard, gotany, i, j, count;
693 CHAR line[150], *build[MAXPARS];
694 REGISTER CHAR *name, *comname, *inter;
695 REGISTER MACROPACK *pack, *thispack;
696 REGISTER VARIABLE *var;
697
698 /* count the number of macros in each package */
699 for(pack=us_macropacktop; pack!=NOMACROPACK; pack=pack->nextmacropack)
700 pack->total = 0;
701 keyboard = gotany = 0;
702 for(i=0; i<us_tool->numvar; i++)
703 {
704 if (namesamen(makename(us_tool->firstvar[i].key), x_("USER_macro_"), 11) == 0)
705 {
706 var = &us_tool->firstvar[i];
707 if (getlength(var) <= 3) continue;
708 count = us_parsecommand(((CHAR **)var->addr)[0], build);
709 for(j=0; j<count; j++)
710 if (namesamen(build[j], x_("macropack="), 10) == 0)
711 {
712 pack = us_getmacropack(&build[j][10]);
713 if (pack != NOMACROPACK) pack->total++;
714 break;
715 }
716 if (j >= count) keyboard++;
717 gotany++;
718 }
719 }
720 if (gotany == 0)
721 {
722 ttyputmsg(M_("No macros defined"));
723 return;
724 }
725
726 ttyputmsg(M_("---------- Macros by Package ----------"));
727
728 /* now print the macros by package */
729 for(pack = us_macropacktop; ; pack = pack->nextmacropack)
730 {
731 if (pack == NOMACROPACK)
732 {
733 if (keyboard == 0) break;
734 name = M_("Keyboard-defined");
735 } else
736 {
737 if (pack->total == 0) continue;
738 name = pack->packname;
739 }
740 (void)estrcpy(line, name);
741 (void)estrcat(line, M_(" macros:"));
742 len = estrlen(line);
743 inter = x_("");
744 for(i=0; i<us_tool->numvar; i++)
745 if (namesamen(makename(us_tool->firstvar[i].key), x_("USER_macro_"), 11) == 0)
746 {
747 var = &us_tool->firstvar[i];
748 if (getlength(var) <= 3) continue;
749 count = us_parsecommand(((CHAR **)var->addr)[0], build);
750 thispack = NOMACROPACK;
751 for(j=0; j<count; j++)
752 if (namesamen(build[j], x_("macropack="), 10) == 0)
753 {
754 thispack = us_getmacropack(&build[j][10]);
755 break;
756 }
757 if (thispack != pack) continue;
758 (void)estrcat(line, inter); len += estrlen(inter);
759 inter = x_(",");
760 comname = &makename(var->key)[11];
761 coms = estrlen(comname) + 2;
762 if (len + coms >= MESSAGESWIDTH)
763 {
764 ttyputmsg(line); (void)estrcpy(line, x_(" ")); len = 2;
765 }
766 (void)estrcat(line, x_(" "));
767 (void)estrcat(line, comname); len += coms;
768
769 }
770 if (len > 2) ttyputmsg(line);
771 if (pack == NOMACROPACK) break;
772 }
773 }
774
775 /*
776 * print macro "mac". Show every command in the macro.
777 */
us_printmacro(VARIABLE * mac)778 void us_printmacro(VARIABLE *mac)
779 {
780 REGISTER INTBIG j, len;
781
782 if (mac == NOVARIABLE) return;
783 len = getlength(mac);
784 if (len <= 3)
785 {
786 ttyputmsg(M_("Macro '%s' is not defined"), &makename(mac->key)[11]);
787 return;
788 }
789
790 ttyputmsg(M_("Macro '%s' has %ld %s"), &makename(mac->key)[11], len-3,
791 makeplural(M_("command"), len-3));
792 for(j=3; j<len; j++) ttyputmsg(x_(" %s"), ((CHAR **)mac->addr)[j]);
793 }
794
795 static struct
796 {
797 CHAR *typestring;
798 INTBIG typecode;
799 } us_vartypename[] =
800 {
801 {x_("Unknown"), VUNKNOWN},
802 {x_("Integer"), VINTEGER},
803 {x_("Address"), VADDRESS},
804 {x_("Character"), VCHAR},
805 {x_("String"), VSTRING},
806 {x_("Float"), VFLOAT},
807 {x_("Double"), VDOUBLE},
808 {x_("Nodeinst"), VNODEINST},
809 {x_("Nodeproto"), VNODEPROTO},
810 {x_("Portarcinst"), VPORTARCINST},
811 {x_("Portexpinst"), VPORTEXPINST},
812 {x_("Portproto"), VPORTPROTO},
813 {x_("Arcinst"), VARCINST},
814 {x_("Arcproto"), VARCPROTO},
815 {x_("Geometry"), VGEOM},
816 {x_("Library"), VLIBRARY},
817 {x_("Technology"), VTECHNOLOGY},
818 {x_("Tool"), VTOOL},
819 {x_("R-tree"), VRTNODE},
820 {x_("Fixed-Point"), VFRACT},
821 {x_("Network"), VNETWORK},
822 {x_("View"), VVIEW},
823 {x_("WindowPart"), VWINDOWPART},
824 {x_("Graphics"), VGRAPHICS},
825 {x_("Short"), VSHORT},
826 {x_("Boolean"), VBOOLEAN},
827 {x_("Constraint"), VCONSTRAINT},
828 {x_("General"), VGENERAL},
829 {x_("Window-Frame"), VWINDOWFRAME},
830 {x_("Polygon"), VPOLYGON},
831 {NULL, 0}
832 };
833
us_variabletypename(INTBIG type)834 CHAR *us_variabletypename(INTBIG type)
835 {
836 INTBIG i;
837
838 for(i=0; us_vartypename[i].typestring != 0; i++)
839 if (us_vartypename[i].typecode == (type&VTYPE))
840 return(us_vartypename[i].typestring);
841 return(x_("unknown"));
842 }
843
us_variabletypevalue(CHAR * name)844 INTBIG us_variabletypevalue(CHAR *name)
845 {
846 INTBIG i;
847
848 for(i=0; us_vartypename[i].typestring != 0; i++)
849 if (namesame(name, us_vartypename[i].typestring) == 0)
850 return(us_vartypename[i].typecode);
851 return(0);
852 }
853
854 /*
855 * routine to describe variable "var". If "index" is nonnegative then describe
856 * entry "index" of an array variable. The description is returned.
857 */
us_variableattributes(VARIABLE * var,INTBIG aindex)858 CHAR *us_variableattributes(VARIABLE *var, INTBIG aindex)
859 {
860 CHAR *arr, line[30];
861 REGISTER INTBIG len;
862 REGISTER void *infstr;
863
864 if ((var->type & VISARRAY) == 0 || aindex >= 0) arr = x_(""); else
865 {
866 len = getlength(var);
867 if (len == 0) arr = x_(" array[]"); else
868 {
869 if ((var->type&VTYPE) == VGENERAL) len /= 2;
870 (void)esnprintf(line, 30, x_(" array[%ld]"), len);
871 arr = line;
872 }
873 }
874 infstr = initinfstr();
875 if ((var->type&VDONTSAVE) != 0) addstringtoinfstr(infstr, _("Temporary "));
876 if ((var->type&VDISPLAY) != 0)
877 {
878 addstringtoinfstr(infstr, _("Displayable("));
879 addstringtoinfstr(infstr, us_describetextdescript(var->textdescript));
880 addstringtoinfstr(infstr, x_(") "));
881 }
882 if ((var->type&(VCODE1|VCODE2)) != 0)
883 {
884 switch (var->type&(VCODE1|VCODE2))
885 {
886 case VLISP: addstringtoinfstr(infstr, x_("LISP ")); break;
887 case VTCL: addstringtoinfstr(infstr, x_("TCL ")); break;
888 case VJAVA: addstringtoinfstr(infstr, x_("Java ")); break;
889 }
890 }
891 addstringtoinfstr(infstr, us_variabletypename(var->type));
892 addstringtoinfstr(infstr, arr);
893 return(returninfstr(infstr));
894 }
895
896 /* routine to recursively count and print the nodes in cell "cell" */
us_describecontents(NODEPROTO * cell)897 void us_describecontents(NODEPROTO *cell)
898 {
899 REGISTER INTBIG i;
900 REGISTER NODEPROTO *np;
901 REGISTER LIBRARY *lib, *printlib;
902 REGISTER TECHNOLOGY *curtech, *printtech, *tech;
903 REGISTER NODEPROTO **sortedcells;
904
905 /* first zero the count of each nodeproto */
906 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
907 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
908 np->temp1 = 0;
909 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
910 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
911 np->temp1 = 0;
912
913 /* now look at every object recursively in this cell */
914 us_addobjects(cell);
915
916 /* print the totals */
917 ttyputmsg(_("Contents of cell %s:"), describenodeproto(cell));
918 printtech = NOTECHNOLOGY;
919 for(curtech = el_technologies; curtech != NOTECHNOLOGY; curtech = curtech->nexttechnology)
920 {
921 for(np = curtech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
922 if (np->temp1 != 0)
923 {
924 if (curtech != printtech)
925 {
926 ttyputmsg(_("%s technology:"), curtech->techname);
927 printtech = curtech;
928 }
929 ttyputmsg(_("%6d %s %s"), np->temp1, describenodeproto(np),
930 makeplural(_("node"), np->temp1));
931 }
932 }
933 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
934 {
935 sortedcells = us_sortlib(lib, (CHAR *)0);
936 if (sortedcells == 0) ttyputnomemory(); else
937 {
938 printlib = NOLIBRARY;
939 for(i = 0; sortedcells[i] != NONODEPROTO; i++)
940 {
941 np = sortedcells[i];
942 if (np->temp1 == 0) continue;
943 if (lib != printlib)
944 {
945 ttyputmsg(_("%s library:"), lib->libname);
946 printlib = lib;
947 }
948 ttyputmsg(_("%6d %s %s"), np->temp1, nldescribenodeproto(np),
949 makeplural(_("node"), np->temp1));
950 }
951 efree((CHAR *)sortedcells);
952 }
953 }
954 }
955
956 /*
957 * routine to recursively examine cell "np" and update the number of
958 * instantiated primitive nodeprotos in the "temp1" field of the nodeprotos.
959 */
us_addobjects(NODEPROTO * np)960 void us_addobjects(NODEPROTO *np)
961 {
962 REGISTER NODEINST *ni;
963 REGISTER NODEPROTO *cnp;
964
965 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
966 {
967 ni->proto->temp1++;
968 if (ni->proto->primindex != 0) continue;
969
970 /* ignore recursive references (showing icon in contents) */
971 if (isiconof(ni->proto, np)) continue;
972 cnp = contentsview(ni->proto);
973 if (cnp == NONODEPROTO) cnp = ni->proto;
974 us_addobjects(cnp);
975 }
976 }
977
978 static struct
979 {
980 NODEPROTO **prim;
981 INTBIG bits;
982 CHAR *statusmessage;
983 } us_specialstatus[] =
984 {
985 {&sch_transistorprim, TRANNMOS, x_("nMOS")},
986 {&sch_transistorprim, TRANDMOS, x_("dMOS")},
987 {&sch_transistorprim, TRANPMOS, x_("pMOS")},
988 {&sch_transistorprim, TRANNPN, x_("NPN")},
989 {&sch_transistorprim, TRANPNP, x_("PNP")},
990 {&sch_transistorprim, TRANNJFET, x_("NJFET")},
991 {&sch_transistorprim, TRANPJFET, x_("PJFET")},
992 {&sch_transistorprim, TRANDMES, x_("DMES")},
993 {&sch_transistorprim, TRANEMES, x_("EMES")},
994 {&sch_transistor4prim,TRANNMOS, x_("nMOS")},
995 {&sch_transistor4prim,TRANDMOS, x_("dMOS")},
996 {&sch_transistor4prim,TRANPMOS, x_("pMOS")},
997 {&sch_transistor4prim,TRANNPN, x_("NPN")},
998 {&sch_transistor4prim,TRANPNP, x_("PNP")},
999 {&sch_transistor4prim,TRANNJFET, x_("NJFET")},
1000 {&sch_transistor4prim,TRANPJFET, x_("PJFET")},
1001 {&sch_transistor4prim,TRANDMES, x_("DMES")},
1002 {&sch_transistor4prim,TRANEMES, x_("EMES")},
1003 {&sch_twoportprim, TWOPVCCS, x_("VCCS")},
1004 {&sch_twoportprim, TWOPCCVS, x_("CCVS")},
1005 {&sch_twoportprim, TWOPVCVS, x_("VCVS")},
1006 {&sch_twoportprim, TWOPCCCS, x_("CCCS")},
1007 {&sch_twoportprim, TWOPTLINE, x_("Transmission")},
1008 {&sch_diodeprim, DIODEZENER, x_("Zener")},
1009 {&sch_capacitorprim, CAPACELEC, x_("Electrolytic")},
1010 {&sch_ffprim, FFTYPERS, x_("RS")},
1011 {&sch_ffprim, FFTYPEJK, x_("JK")},
1012 {&sch_ffprim, FFTYPED, x_("D")},
1013 {&sch_ffprim, FFTYPET, x_("T")},
1014 {0, 0, 0}
1015 };
1016
1017 /*
1018 * Routine to describe the node in the commandbinding structure "commandbinding".
1019 */
us_describemenunode(COMMANDBINDING * commandbinding)1020 CHAR *us_describemenunode(COMMANDBINDING *commandbinding)
1021 {
1022 REGISTER INTBIG bits;
1023
1024 if (commandbinding->menumessage == 0) bits = 0; else
1025 bits = myatoi(commandbinding->menumessage);
1026 return(us_describenodeinsttype(commandbinding->nodeglyph, NONODEINST, bits));
1027 }
1028
1029 /*
1030 * Routine to return a description of node "np" that is qualified with bits "bits".
1031 * It may also be qualified by having an instance "ni" (but it may be NONODEINST).
1032 */
us_describenodeinsttype(NODEPROTO * np,NODEINST * ni,INTBIG bits)1033 CHAR *us_describenodeinsttype(NODEPROTO *np, NODEINST *ni, INTBIG bits)
1034 {
1035 REGISTER INTBIG i;
1036 REGISTER CHAR *pt;
1037 REGISTER void *infstr;
1038
1039 infstr = initinfstr();
1040 addstringtoinfstr(infstr, describenodeproto(np));
1041 for(i=0; us_specialstatus[i].prim != 0; i++)
1042 if (us_specialstatus[i].bits == bits &&
1043 *us_specialstatus[i].prim == np) break;
1044 if (us_specialstatus[i].prim != 0)
1045 {
1046 formatinfstr(infstr, x_(" (%s)"), us_specialstatus[i].statusmessage);
1047 } else
1048 {
1049 /* add information if from technology editor */
1050 if (ni != NONODEINST)
1051 {
1052 pt = us_teceddescribenode(ni);
1053 if (pt != 0) formatinfstr(infstr, x_(" (%s)"), pt);
1054 }
1055 }
1056 return(returninfstr(infstr));
1057 }
1058
1059 /*
1060 * routine to sort the cells in library "lib" by cell name and return an
1061 * array of NODEPROTO pointers (terminating with NONODEPROTO). If "matchspec"
1062 * is nonzero, it is a string that forces wildcard matching of cell names.
1063 */
us_sortlib(LIBRARY * lib,CHAR * matchspec)1064 NODEPROTO **us_sortlib(LIBRARY *lib, CHAR *matchspec)
1065 {
1066 REGISTER NODEPROTO **sortindex, *np;
1067 REGISTER INTBIG total, i;
1068 REGISTER CHAR *pt;
1069
1070 /* remove library name if it is part of spec */
1071 if (matchspec != 0)
1072 {
1073 for(pt = matchspec; *pt != 0; pt++) if (*pt == ':') break;
1074 if (*pt == ':') matchspec = pt+1;
1075 }
1076
1077 /* count the number of cells in the library */
1078 total = 0;
1079 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1080 if (us_wildmatch(nldescribenodeproto(np), matchspec)) total++;
1081
1082 /* allocate array for sorting entries */
1083 sortindex = (NODEPROTO **)emalloc(((total+1) * (sizeof (NODEPROTO *))), el_tempcluster);
1084 if (sortindex == 0) return(0);
1085 for(np = lib->firstnodeproto, i = 0; np != NONODEPROTO; np = np->nextnodeproto)
1086 if (us_wildmatch(nldescribenodeproto(np), matchspec))
1087 sortindex[i++] = np;
1088 sortindex[i] = NONODEPROTO;
1089
1090 /* sort the cell names */
1091 esort(sortindex, total, sizeof (NODEPROTO *), sort_cellnameascending);
1092 return(sortindex);
1093 }
1094
1095 /*
1096 * routine to match a name in "name" with a wildcard specification in "spec".
1097 * If "spec" is zero, all names are valid. Returns true if the name matches.
1098 */
us_wildmatch(CHAR * name,CHAR * spec)1099 BOOLEAN us_wildmatch(CHAR *name, CHAR *spec)
1100 {
1101 REGISTER CHAR *pt, *pt2;
1102 REGISTER CHAR c1, c2;
1103
1104 if (spec == 0) return(TRUE);
1105
1106 pt = name;
1107 pt2 = spec;
1108 for(;;)
1109 {
1110 if (*pt == 0 && *pt2 == 0) break;
1111 if (*pt != 0 && *pt2 == '?')
1112 {
1113 pt++;
1114 pt2++;
1115 continue;
1116 }
1117 if (*pt2 == '*')
1118 {
1119 for(;;)
1120 {
1121 if (us_wildmatch(pt, &pt2[1]) != 0) return(TRUE);
1122 if (*pt == 0) break;
1123 pt++;
1124 }
1125 return(FALSE);
1126 }
1127 if (isupper(*pt)) c1 = tolower(*pt); else c1 = *pt;
1128 if (isupper(*pt2)) c2 = tolower(*pt2); else c2 = *pt2;
1129 if (c1 != c2) return(FALSE);
1130 pt++;
1131 pt2++;
1132 }
1133 return(TRUE);
1134 }
1135
1136 /* routine to print the tool information about nodeinst "ni" */
us_printnodetoolinfo(NODEINST * ni)1137 void us_printnodetoolinfo(NODEINST *ni)
1138 {
1139 static struct explanation explain[] =
1140 {
1141 {DEADN, -1, N_("dead")},
1142 {NEXPAND, -1, N_("expand")},
1143 {WIPED, -1, N_("wiped")},
1144 {NSHORT, -1, N_("short")},
1145 {0, -1, NULL}
1146 };
1147 us_explaintool(ni->userbits, explain);
1148 }
1149
1150 /* routine to print the tool information about arcinst "ai" */
us_printarctoolinfo(ARCINST * ai)1151 void us_printarctoolinfo(ARCINST *ai)
1152 {
1153 static struct explanation explain[] =
1154 {
1155 {FIXED, -1, N_("rigid")},
1156 {CANTSLIDE, -1, N_("rigid-in-ports")},
1157 {FIXANG, -1, N_("fixed-angle")},
1158 {DEADA, -1, N_("dead")},
1159 {AANGLE, AANGLESH, N_("angle")},
1160 {ASHORT, -1, N_("short")},
1161 {AFUNCTION, APBUS<<AFUNCTIONSH, N_("bus")},
1162 {NOEXTEND, -1, N_("ends-shortened")},
1163 {ISNEGATED, -1, N_("negated")},
1164 {ISDIRECTIONAL, -1, N_("directional")},
1165 {NOTEND0, -1, N_("skip-tail")},
1166 {NOTEND1, -1, N_("skip-head")},
1167 {REVERSEEND, -1, N_("direction-reversed")},
1168 {0, -1, NULL}
1169 };
1170 us_explaintool(ai->userbits, explain);
1171 }
1172
1173 /* helper routine for "us_printnodetoolinfo" and "us_printarctoolinfo" */
us_explaintool(INTBIG bits,struct explanation explain[])1174 void us_explaintool(INTBIG bits, struct explanation explain[])
1175 {
1176 REGISTER INTBIG j, k;
1177 CHAR partial[40];
1178 REGISTER void *infstr;
1179
1180 /* print the tool bit information */
1181 infstr = initinfstr();
1182 (void)esnprintf(partial, 40, _("User state = %ld"), bits);
1183 addstringtoinfstr(infstr, partial);
1184 k = 0;
1185 for(j=0; explain[j].bit != 0; j++)
1186 {
1187 if (explain[j].shift != -1)
1188 {
1189 if (k == 0) addtoinfstr(infstr, '('); else
1190 addstringtoinfstr(infstr, x_(", "));
1191 addstringtoinfstr(infstr, TRANSLATE(explain[j].name));
1192 addtoinfstr(infstr, '=');
1193 (void)esnprintf(partial, 40, x_("%ld"),(bits&explain[j].bit)>>explain[j].shift);
1194 addstringtoinfstr(infstr, partial);
1195 k++;
1196 continue;
1197 }
1198 if ((bits & explain[j].bit) == 0) continue;
1199 if (k == 0) addtoinfstr(infstr, '('); else addstringtoinfstr(infstr, x_(", "));
1200 addstringtoinfstr(infstr, TRANSLATE(explain[j].name));
1201 k++;
1202 }
1203 if (k != 0) addtoinfstr(infstr, ')');
1204 ttyputmsg(x_("%s"), returninfstr(infstr));
1205 }
1206
1207 /*
1208 * routine to print information about port prototype "pp" on nodeinst "ni".
1209 * If the port prototype's "temp1" is nonzero, this port has already been
1210 * mentioned and should not be done again.
1211 */
us_chatportproto(NODEINST * ni,PORTPROTO * pp)1212 void us_chatportproto(NODEINST *ni, PORTPROTO *pp)
1213 {
1214 REGISTER PORTARCINST *pi;
1215 REGISTER PORTEXPINST *pe;
1216 REGISTER ARCINST *ai;
1217 REGISTER INTBIG i, lambda;
1218 INTBIG lx, hx, ly, hy;
1219 REGISTER CHAR *activity;
1220 CHAR locx[40], locy[40];
1221 static POLYGON *poly = NOPOLYGON;
1222 REGISTER void *infstr;
1223
1224 /* get polygon */
1225 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
1226
1227 /* if this port has already been discussed, quit now */
1228 if (pp->temp1 != 0) return;
1229 pp->temp1++;
1230
1231 /* talk about the port prototype */
1232 lambda = lambdaofnode(ni);
1233 infstr = initinfstr();
1234 activity = describeportbits(pp->userbits);
1235 if (*activity != 0)
1236 {
1237 formatinfstr(infstr, _("%s port %s connects to "), activity, pp->protoname);
1238 } else
1239 {
1240 formatinfstr(infstr, _("Port %s connects to "), pp->protoname);
1241 }
1242 for(i=0; pp->connects[i] != NOARCPROTO; i++)
1243 {
1244 if (i != 0) addstringtoinfstr(infstr, x_(", "));
1245 addstringtoinfstr(infstr, pp->connects[i]->protoname);
1246 }
1247 ttyputmsg(x_("%s"), returninfstr(infstr));
1248
1249 if (pp->subnodeinst == NONODEINST)
1250 {
1251 shapeportpoly(ni, pp, poly, FALSE);
1252
1253 /* see if the port is a single point */
1254 for(i=1; i<poly->count; i++)
1255 if (poly->xv[i] != poly->xv[i-1] || poly->yv[i] != poly->yv[i-1]) break;
1256 if (i >= poly->count)
1257 {
1258 ttyputmsg(_(" Located at (%s, %s)"), latoa(poly->xv[0], lambda), latoa(poly->yv[0], lambda));
1259 } else if (isbox(poly, &lx,&hx, &ly,&hy))
1260 {
1261 if (lx == hx) (void)esnprintf(locx, 40, _("at %s"), latoa(lx, lambda)); else
1262 (void)esnprintf(locx, 40, _("from %s to %s"), latoa(lx, lambda), latoa(hx, lambda));
1263 if (ly == hy) (void)esnprintf(locy, 40, _("at %s"), latoa(ly, lambda)); else
1264 (void)esnprintf(locy, 40, _("from %s to %s"), latoa(ly, lambda), latoa(hy, lambda));
1265 ttyputmsg(_(" Located %s in X and %s in Y"), locx, locy);
1266 } else
1267 {
1268 infstr = initinfstr();
1269 for(i=0; i<poly->count; i++)
1270 formatinfstr(infstr, x_(" (%s, %s)"), latoa(poly->xv[i], lambda), latoa(poly->yv[i], lambda));
1271 ttyputmsg(_(" Located inside polygon%s"), returninfstr(infstr));
1272 }
1273 } else ttyputmsg(_(" Located at subnode %s subport %s"),
1274 describenodeinst(pp->subnodeinst), pp->subportproto->protoname);
1275
1276 /* talk about any arcs on this prototype */
1277 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1278 {
1279 if (pi->proto != pp) continue;
1280 ai = pi->conarcinst;
1281 if (ai->end[0].portarcinst == pi) i = 0; else i = 1;
1282 ttyputmsg(_(" Connected at (%s,%s) to %s"), latoa(ai->end[i].xpos, lambda),
1283 latoa(ai->end[i].ypos, lambda), describearcinst(ai));
1284 }
1285
1286 /* talk about any exports of this prototype */
1287 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1288 if (pe->proto == pp)
1289 {
1290 infstr = initinfstr();
1291 formatinfstr(infstr, _(" Available as %s export '%s' (label %s"),
1292 describeportbits(pe->exportproto->userbits), pe->exportproto->protoname,
1293 us_describetextdescript(pe->exportproto->textdescript));
1294 if ((pe->exportproto->userbits&PORTDRAWN) != 0) addstringtoinfstr(infstr, _(",always-drawn"));
1295 if ((pe->exportproto->userbits&BODYONLY) != 0) addstringtoinfstr(infstr, _(",only-on-body"));
1296 addstringtoinfstr(infstr, x_(") "));
1297 ttyputmsg(x_("%s"), returninfstr(infstr));
1298 }
1299 }
1300
1301 /*
1302 * routine to construct a string that describes the text descriptor field
1303 * in "descript". The string has the form "POSITION+(DX,DY),SIZE" if there
1304 * is an offset, or "POSITION,SIZE" if there is not. The string is returned.
1305 */
us_describetextdescript(UINTBIG * descript)1306 CHAR *us_describetextdescript(UINTBIG *descript)
1307 {
1308 REGISTER INTBIG xdist, ydist;
1309 CHAR offset[50];
1310 REGISTER void *infstr;
1311
1312 infstr = initinfstr();
1313 addstringtoinfstr(infstr, us_describestyle(TDGETPOS(descript)));
1314 if (TDGETXOFF(descript) != 0 || TDGETYOFF(descript) != 0)
1315 {
1316 xdist = TDGETXOFF(descript);
1317 ydist = TDGETYOFF(descript);
1318 (void)esnprintf(offset, 50, x_("+(%s,%s)"), frtoa(xdist*WHOLE/4), frtoa(ydist*WHOLE/4));
1319 addstringtoinfstr(infstr, offset);
1320 }
1321 addtoinfstr(infstr, ',');
1322 addstringtoinfstr(infstr, us_describefont(TDGETSIZE(descript)));
1323 return(returninfstr(infstr));
1324 }
1325
1326 /*
1327 * routine to return a string describing text style "style".
1328 */
us_describestyle(INTBIG style)1329 CHAR *us_describestyle(INTBIG style)
1330 {
1331 switch (style)
1332 {
1333 case VTPOSCENT: return(_("centered"));
1334 case VTPOSBOXED: return(_("boxed"));
1335 case VTPOSUP: return(_("up"));
1336 case VTPOSDOWN: return(_("down"));
1337 case VTPOSLEFT: return(_("left"));
1338 case VTPOSRIGHT: return(_("right"));
1339 case VTPOSUPLEFT: return(_("up-left"));
1340 case VTPOSUPRIGHT: return(_("up-right"));
1341 case VTPOSDOWNLEFT: return(_("down-left"));
1342 case VTPOSDOWNRIGHT: return(_("down-right"));
1343 }
1344 return(x_("?"));
1345 }
1346
1347 /*
1348 * routine to return a string describing text font "font".
1349 */
us_describefont(INTBIG font)1350 CHAR *us_describefont(INTBIG font)
1351 {
1352 static CHAR description[60];
1353 if (TXTGETPOINTS(font) != 0)
1354 {
1355 esnprintf(description, 60, _("%ld-points"), TXTGETPOINTS(font));
1356 return(description);
1357 }
1358 if (TXTGETQLAMBDA(font) != 0)
1359 {
1360 esnprintf(description, 60, _("%s-lambda"), frtoa(TXTGETQLAMBDA(font) * WHOLE / 4));
1361 return(description);
1362 }
1363 return(x_("?"));
1364 }
1365
1366 /*
1367 * Routine to return the type of nonlayout text that is in variable "var".
1368 */
us_invisiblepintextname(VARIABLE * var)1369 CHAR *us_invisiblepintextname(VARIABLE *var)
1370 {
1371 if (namesame(makename(var->key), x_("VERILOG_code")) == 0)
1372 return(_("Verilog code"));
1373 if (namesame(makename(var->key), x_("VERILOG_declaration")) == 0)
1374 return(_("Verilog declaration"));
1375 if (namesame(makename(var->key), x_("SIM_spice_card")) == 0)
1376 return(_("SPICE card"));
1377 return(_("Nonlayout Text"));
1378 }
1379
1380 typedef struct
1381 {
1382 CHAR *origvarname;
1383 CHAR *uservarname;
1384 } USERVARIABLES;
1385
1386 USERVARIABLES us_uservariables[] =
1387 {
1388 {x_("ARC_name"), N_("Arc Name")},
1389 {x_("ARC_radius"), N_("Arc Radius")},
1390 {x_("ART_color"), N_("Color")},
1391 {x_("ART_degrees"), N_("Number of Degrees")},
1392 {x_("ART_message"), N_("Text")},
1393 {x_("NET_ncc_match"), N_("NCC equivalence")},
1394 {x_("NET_ncc_forcedassociation"),N_("NCC association")},
1395 {x_("NODE_name"), N_("Node Name")},
1396 {x_("SCHEM_capacitance"), N_("Capacitance")},
1397 {x_("SCHEM_diode"), N_("Diode Size")},
1398 {x_("SCHEM_inductance"), N_("Inductance")},
1399 {x_("SCHEM_resistance"), N_("Resistance")},
1400 {x_("SIM_fall_delay"), N_("Fall Delay")},
1401 {x_("SIM_fasthenry_group_name"), N_("FastHenry Group")},
1402 {x_("SIM_rise_delay"), N_("Rise Delay")},
1403 {x_("SIM_spice_model"), N_("SPICE model")},
1404 {x_("transistor_width"), N_("Transistor Width")},
1405 {x_("SCHEM_global_name"), N_("Global Signal Name")},
1406 {0, 0}
1407 };
1408
1409 /*
1410 * Routine to see if variable name "name" is a known variable. If
1411 * so, returns a better name for it. If not, returns zero.
1412 */
us_bettervariablename(CHAR * name)1413 CHAR *us_bettervariablename(CHAR *name)
1414 {
1415 REGISTER INTBIG i;
1416
1417 /* handle standard variable names */
1418 for(i=0; us_uservariables[i].origvarname != 0; i++)
1419 {
1420 if (namesame(name, us_uservariables[i].origvarname) == 0)
1421 return(TRANSLATE(us_uservariables[i].uservarname));
1422 }
1423 return(0);
1424 }
1425
1426 /*
1427 * Routine to see if variable "var" should have a units qualifier after it.
1428 * If so, returns the type. If not, returns zero.
1429 */
us_variableunits(VARIABLE * var)1430 CHAR *us_variableunits(VARIABLE *var)
1431 {
1432 REGISTER INTBIG units;
1433
1434 /* specialized fields that adjust with units */
1435 units = TDGETUNITS(var->textdescript);
1436 switch (units)
1437 {
1438 case VTUNITSRES: /* resistance */
1439 return(TRANSLATE(us_resistancenames[(us_electricalunits&INTERNALRESUNITS) >> INTERNALRESUNITSSH]));
1440 case VTUNITSCAP: /* capacitance */
1441 return(TRANSLATE(us_capacitancenames[(us_electricalunits&INTERNALCAPUNITS) >> INTERNALCAPUNITSSH]));
1442 case VTUNITSIND: /* inductance */
1443 return(TRANSLATE(us_inductancenames[(us_electricalunits&INTERNALINDUNITS) >> INTERNALINDUNITSSH]));
1444 case VTUNITSCUR: /* current */
1445 return(TRANSLATE(us_currentnames[(us_electricalunits&INTERNALCURUNITS) >> INTERNALCURUNITSSH]));
1446 case VTUNITSVOLT: /* voltage */
1447 return(TRANSLATE(us_voltagenames[(us_electricalunits&INTERNALVOLTUNITS) >> INTERNALVOLTUNITSSH]));
1448 case VTUNITSTIME: /* time */
1449 return(TRANSLATE(us_timenames[(us_electricalunits&INTERNALTIMEUNITS) >> INTERNALTIMEUNITSSH]));
1450 }
1451 return(0);
1452 }
1453
1454 /*
1455 * Routine to return a user-friendly name of variable "var".
1456 */
us_trueattributename(VARIABLE * var)1457 CHAR *us_trueattributename(VARIABLE *var)
1458 {
1459 REGISTER CHAR *pt, *bettername, *unitname;
1460 REGISTER void *infstr;
1461
1462 infstr = initinfstr();
1463 pt = makename(var->key);
1464 if (namesamen(pt, x_("ATTR_"), 5) == 0)
1465 {
1466 if (TDGETISPARAM(var->textdescript) != 0)
1467 formatinfstr(infstr, _("Parameter '%s'"), &pt[5]); else
1468 formatinfstr(infstr, _("Attribute '%s'"), &pt[5]);
1469 } else
1470 {
1471 bettername = us_bettervariablename(pt);
1472 if (bettername != 0) addstringtoinfstr(infstr, bettername); else
1473 formatinfstr(infstr, _("Variable '%s'"), pt);
1474 }
1475 unitname = us_variableunits(var);
1476 if (unitname != 0) formatinfstr(infstr, x_(" (%s)"), unitname);
1477 return(returninfstr(infstr));
1478 }
1479
1480 /*
1481 * routine to print a description of color map entry "ind"
1482 */
us_printcolorvalue(INTBIG ind)1483 void us_printcolorvalue(INTBIG ind)
1484 {
1485 GRAPHICS *desc;
1486 CHAR line[40];
1487 REGISTER INTBIG i, j, high;
1488 REGISTER VARIABLE *varred, *vargreen, *varblue;
1489 REGISTER void *infstr;
1490
1491 /* get color arrays */
1492 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
1493 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
1494 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
1495 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
1496 {
1497 ttyputerr(_("Cannot get current color map"));
1498 return;
1499 }
1500
1501 infstr = initinfstr();
1502 if ((ind&(LAYERH|LAYERG)) == 0)
1503 {
1504 (void)esnprintf(line, 40, _("Entry %ld"), ind);
1505 addstringtoinfstr(infstr, line);
1506 j = 0;
1507 high = el_curtech->layercount;
1508 for(i=0; i<high; i++)
1509 {
1510 desc = el_curtech->layers[i];
1511 if (desc->bits == LAYERO && desc->col != ind) continue;
1512 if (desc->bits != LAYERO && ((desc->col&ind) == 0 || (ind&LAYEROE) != 0)) continue;
1513 if (j == 0) addstringtoinfstr(infstr, x_(" (")); else
1514 addtoinfstr(infstr, ',');
1515 j++;
1516 addstringtoinfstr(infstr, layername(el_curtech, i));
1517 }
1518 if (j != 0) addtoinfstr(infstr, ')');
1519 addstringtoinfstr(infstr, _(" is"));
1520 } else
1521 {
1522 if ((ind&LAYERG) != 0) addstringtoinfstr(infstr, _("Grid entry is")); else
1523 if ((ind&LAYERH) != 0) addstringtoinfstr(infstr, _("Highlight entry is"));
1524 }
1525 (void)esnprintf(line, 40, _(" color (%ld,%ld,%ld)"), ((INTBIG *)varred->addr)[ind],
1526 ((INTBIG *)vargreen->addr)[ind], ((INTBIG *)varblue->addr)[ind]);
1527 addstringtoinfstr(infstr, line);
1528 ttyputmsg(x_("%s"), returninfstr(infstr));
1529 }
1530
1531 /*
1532 * routine to make a line of text that describes cell "np". The text
1533 * includes the cell name, version, creation, and revision dates. The
1534 * amount of space to leave for the cell name is "maxlen" characters
1535 * (which is negative if dumping to a file).
1536 */
us_makecellline(NODEPROTO * np,INTBIG maxlen)1537 CHAR *us_makecellline(NODEPROTO *np, INTBIG maxlen)
1538 {
1539 CHAR line[40];
1540 REGISTER INTBIG l, i, gooddrc, len, total, lambda;
1541 INTBIG year, month, mday, hour, minute, second;
1542 REGISTER CHAR *pt;
1543 REGISTER VARIABLE *var;
1544 REGISTER NODEINST *ni;
1545 UINTBIG lastgooddate;
1546 REGISTER void *infstr;
1547
1548 infstr = initinfstr();
1549 pt = describenodeproto(np);
1550 addstringtoinfstr(infstr, pt);
1551 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1552 {
1553 l = estrlen(pt);
1554 for(i=l; i<maxlen; i++) addtoinfstr(infstr, ' ');
1555 }
1556
1557 /* add the version number */
1558 (void)esnprintf(line, 40, x_("%5ld"), np->version);
1559 addstringtoinfstr(infstr, line);
1560 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1561 addstringtoinfstr(infstr, x_(" "));
1562
1563 /* add the creation date */
1564 if (np->creationdate == 0)
1565 {
1566 if (maxlen < 0) addstringtoinfstr(infstr, _("UNRECORDED")); else
1567 addstringtoinfstr(infstr, _(" UNRECORDED "));
1568 } else
1569 {
1570 if (maxlen < 0)
1571 {
1572 parsetime((time_t)np->creationdate, &year, &month, &mday, &hour, &minute, &second);
1573 esnprintf(line, 40, x_("%4ld-%02ld-%02ld %02ld:%02ld:%02ld"), year, month, mday, hour,
1574 minute, second);
1575 addstringtoinfstr(infstr, line);
1576 } else
1577 {
1578 pt = timetostring(np->creationdate);
1579 if (pt == NULL)
1580 {
1581 addstringtoinfstr(infstr, _(" UNAVAILABLE "));
1582 } else
1583 {
1584 for(i=4; i<=9; i++) addtoinfstr(infstr, pt[i]);
1585 for(i=19; i<=23; i++) addtoinfstr(infstr, pt[i]);
1586 for(i=10; i<=18; i++) addtoinfstr(infstr, pt[i]);
1587 }
1588 }
1589 }
1590
1591 /* add the revision date */
1592 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1593 addstringtoinfstr(infstr, x_(" "));
1594 if (np->revisiondate == 0)
1595 {
1596 if (maxlen < 0) addstringtoinfstr(infstr, _("UNRECORDED")); else
1597 addstringtoinfstr(infstr, _(" UNRECORDED "));
1598 } else
1599 {
1600 if (maxlen < 0)
1601 {
1602 parsetime((time_t)np->revisiondate, &year, &month, &mday, &hour, &minute, &second);
1603 esnprintf(line, 40, x_("%4ld-%02ld-%02ld %02ld:%02ld:%02ld"), year, month, mday, hour,
1604 minute, second);
1605 addstringtoinfstr(infstr, line);
1606 } else
1607 {
1608 pt = timetostring(np->revisiondate);
1609 if (pt == NULL)
1610 {
1611 addstringtoinfstr(infstr, _(" UNAVAILABLE "));
1612 } else
1613 {
1614 for(i=4; i<=9; i++) addtoinfstr(infstr, pt[i]);
1615 for(i=19; i<=23; i++) addtoinfstr(infstr, pt[i]);
1616 for(i=10; i<=18; i++) addtoinfstr(infstr, pt[i]);
1617 }
1618 }
1619 }
1620
1621 /* add the size */
1622 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1623 addstringtoinfstr(infstr, x_(" "));
1624 if ((np->cellview->viewstate&TEXTVIEW) != 0)
1625 {
1626 var = getvalkey((INTBIG)np, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
1627 if (var == NOVARIABLE) len = 0; else
1628 len = getlength(var);
1629 if (maxlen < 0) esnprintf(line, 40, _("%ld lines"), len); else
1630 esnprintf(line, 40, _("%8ld lines "), len);
1631 addstringtoinfstr(infstr, line);
1632 } else
1633 {
1634 lambda = lambdaofcell(np);
1635 estrcpy(line, latoa(np->highx-np->lowx, lambda));
1636 if (maxlen >= 0)
1637 {
1638 for(i = estrlen(line); i<8; i++) addtoinfstr(infstr, ' ');
1639 }
1640 addstringtoinfstr(infstr, line);
1641 addtoinfstr(infstr, 'x');
1642 estrcpy(line, latoa(np->highy-np->lowy, lambda));
1643 addstringtoinfstr(infstr, line);
1644 if (maxlen >= 0)
1645 {
1646 for(i = estrlen(line); i<8; i++) addtoinfstr(infstr, ' ');
1647 }
1648 }
1649 if (maxlen < 0) addtoinfstr(infstr, '\t');
1650
1651 /* count the number of instances */
1652 total = 0;
1653 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst) total++;
1654 if (maxlen < 0) esnprintf(line, 40, x_("%ld"), total); else
1655 esnprintf(line, 40, x_("%4ld"), total);
1656 addstringtoinfstr(infstr, line);
1657
1658 /* show other factors about the cell */
1659 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1660 addstringtoinfstr(infstr, x_(" "));
1661 if ((np->userbits&NPLOCKED) != 0) addstringtoinfstr(infstr, x_("L")); else
1662 addstringtoinfstr(infstr, x_(" "));
1663 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1664 addstringtoinfstr(infstr, x_(" "));
1665 if ((np->userbits&NPILOCKED) != 0) addstringtoinfstr(infstr, x_("I")); else
1666 addstringtoinfstr(infstr, x_(" "));
1667 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1668 addstringtoinfstr(infstr, x_(" "));
1669 if ((np->userbits&INCELLLIBRARY) != 0) addstringtoinfstr(infstr, x_("C")); else
1670 addstringtoinfstr(infstr, x_(" "));
1671 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1672 addstringtoinfstr(infstr, x_(" "));
1673 gooddrc = 0;
1674 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, dr_lastgooddrckey);
1675 if (var != NOVARIABLE)
1676 {
1677 lastgooddate = (UINTBIG)var->addr;
1678 if (np->revisiondate <= lastgooddate) gooddrc = 1;
1679 }
1680 if (gooddrc != 0) addstringtoinfstr(infstr, x_("D")); else
1681 addstringtoinfstr(infstr, x_(" "));
1682 if (maxlen < 0) addtoinfstr(infstr, '\t'); else
1683 addstringtoinfstr(infstr, x_(" "));
1684 if (net_ncchasmatch(np) != 0) addstringtoinfstr(infstr, x_("N")); else
1685 addstringtoinfstr(infstr, x_(" "));
1686 return(returninfstr(infstr));
1687 }
1688
1689 /******************** KEYBOARD SUPPORT ********************/
1690
1691 /*
1692 * routine to check to see if library "lib" has changed and warn the
1693 * user prior to destroying changes to that library. If "lib" is NOLIBRARY, all
1694 * libraries are checked. "action" is the type of action to be performed:
1695 * 0=quit, 1=close library, 2=replace library
1696 * If the operation can be cancelled, "cancancel" is true. Returns true
1697 * if the operation is to be aborted.
1698 */
us_preventloss(LIBRARY * lib,INTBIG action,BOOLEAN cancancel)1699 BOOLEAN us_preventloss(LIBRARY *lib, INTBIG action, BOOLEAN cancancel)
1700 {
1701 REGISTER INTBIG result, count;
1702 CHAR *par[10];
1703 REGISTER LIBRARY *l;
1704 extern COMCOMP us_yesnop;
1705 REGISTER void *infstr;
1706
1707 for(l = el_curlib; l != NOLIBRARY; l = l->nextlibrary)
1708 {
1709 if ((l->userbits&HIDDENLIBRARY) != 0) continue;
1710 if (lib != NOLIBRARY && lib != l) continue;
1711 if ((l->userbits&(LIBCHANGEDMAJOR|LIBCHANGEDMINOR)) == 0) continue;
1712
1713 infstr = initinfstr();
1714 if ((l->userbits&LIBCHANGEDMAJOR) != 0)
1715 formatinfstr(infstr, _("Library %s has changed significantly. "), l->libname); else
1716 formatinfstr(infstr, _("Library %s has changed insignificantly. "), l->libname);
1717 switch (action)
1718 {
1719 case 0: addstringtoinfstr(infstr, _("Save before quitting?")); break;
1720 case 1: addstringtoinfstr(infstr, _("Save before closing?")); break;
1721 case 2: addstringtoinfstr(infstr, _("Save before replacing?")); break;
1722 }
1723 if (cancancel)
1724 {
1725 result = us_quitdlog(returninfstr(infstr), (action==0 ? 1 : 0));
1726 if (result == 0)
1727 {
1728 ttyputverbose(M_("Keep working"));
1729 return(TRUE);
1730 }
1731 if (result == 1) continue;
1732 if (result == 2) break;
1733 if (result == 3)
1734 {
1735 /* save the library */
1736 makeoptionstemporary(l);
1737 (void)asktool(io_tool, x_("write"), (INTBIG)l, (INTBIG)x_("binary"));
1738 }
1739 } else
1740 {
1741 count = ttygetparam(returninfstr(infstr), &us_yesnop, MAXPARS, par);
1742 if (count > 0 && namesamen(par[0], x_("yes"), estrlen(par[0])) == 0)
1743 {
1744 /* save the library */
1745 makeoptionstemporary(l);
1746 (void)asktool(io_tool, x_("write"), (INTBIG)l, (INTBIG)x_("binary"));
1747 }
1748 }
1749 }
1750
1751 /* also check for option changes on quit */
1752 if (us_optionschanged && action == 0)
1753 {
1754 if (optionshavechanged())
1755 {
1756 if (us_saveoptdlog(TRUE))
1757 {
1758 ttyputverbose(M_("Keep working"));
1759 return(TRUE);
1760 }
1761 }
1762 }
1763 return(FALSE);
1764 }
1765
1766 /*
1767 * Routine to save all options by creating a dummy library and saving it (without
1768 * making options temporary first).
1769 */
us_saveoptions(void)1770 void us_saveoptions(void)
1771 {
1772 REGISTER INTBIG retval;
1773 REGISTER LIBRARY *lib;
1774 REGISTER CHAR *libname, *libfile;
1775
1776 libname = us_tempoptionslibraryname();
1777 libfile = optionsfilepath();
1778 lib = newlibrary(libname, libfile);
1779 if (lib == NOLIBRARY)
1780 {
1781 ttyputerr(_("Cannot create options library %s"), libfile);
1782 return;
1783 }
1784 lib->userbits |= READFROMDISK | HIDDENLIBRARY;
1785 retval = asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("nobackupbinary"));
1786 if (retval != 0) ttyputerr(_("Could not save options library")); else
1787 ttyputmsg(_("Options have been saved to %s"), lib->libfile);
1788 killlibrary(lib);
1789 us_optionschanged = FALSE;
1790
1791 /* recache the options so that the system knows what has changed */
1792 cacheoptionbitvalues();
1793 }
1794
1795 /*
1796 * Routine to construct a temporary library name that doesn't already exist.
1797 */
us_tempoptionslibraryname(void)1798 CHAR *us_tempoptionslibraryname(void)
1799 {
1800 static CHAR libname[256];
1801 REGISTER LIBRARY *lib;
1802 REGISTER INTBIG i;
1803
1804 for(i=1; ; i++)
1805 {
1806 esnprintf(libname, 256, x_("options%ld"), i);
1807 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1808 if (namesame(libname, lib->libname) == 0) break;
1809 if (lib == NOLIBRARY) break;
1810 }
1811 return(libname);
1812 }
1813
1814 /*
1815 * Routine to ensure that everything gets saved. Returns TRUE if something got saved.
1816 */
us_saveeverything(void)1817 BOOLEAN us_saveeverything(void)
1818 {
1819 REGISTER INTBIG total, i, l, retval;
1820 REGISTER LIBRARY *lib, *deplib, **libsave;
1821 REGISTER NODEPROTO *np;
1822 REGISTER NODEINST *ni;
1823 REGISTER BOOLEAN gotsaved;
1824
1825 /* see which libraries need to be saved */
1826 gotsaved = FALSE;
1827 total = 0;
1828 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1829 {
1830 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
1831 if ((lib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) == 0) continue;
1832 total++;
1833 }
1834 if (total == 0) return(gotsaved);
1835 libsave = (LIBRARY **)emalloc(total * (sizeof (LIBRARY *)), el_tempcluster);
1836 if (libsave == 0) return(gotsaved);
1837
1838 /* make a list of the libraries to save */
1839 total = 0;
1840 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1841 {
1842 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
1843 if ((lib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) == 0) continue;
1844 libsave[total++] = lib;
1845 }
1846
1847 /* be sure the most referenced libraries are saved first */
1848 for(i=0; i<total; i++) libsave[i]->temp1 = i;
1849 for(i=0; i<total; i++)
1850 {
1851 lib = libsave[i];
1852 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1853 {
1854 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1855 {
1856 if (ni->proto->primindex != 0) continue;
1857 deplib = ni->proto->lib;
1858 if (deplib == lib) continue;
1859 if (deplib->temp1 <= lib->temp1) continue;
1860 l = deplib->temp1; deplib->temp1 = lib->temp1; lib->temp1 = l;
1861 }
1862 }
1863 }
1864 esort(libsave, total, sizeof (LIBRARY *), us_librarytemp1ascending);
1865
1866 /* now save every library that needs it */
1867 for(i=0; i<total; i++)
1868 {
1869 lib = libsave[i];
1870
1871 /* save the library in binary format */
1872 makeoptionstemporary(lib);
1873 retval = asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("binary"));
1874 restoreoptionstate(lib);
1875 if (retval != 0) continue;
1876 gotsaved = TRUE;
1877 }
1878
1879 /* clean up */
1880 efree((CHAR *)libsave);
1881
1882 /* save options if any have changed */
1883 if (us_optionschanged && gotsaved && us_logrecord != NULL)
1884 {
1885 if (optionshavechanged())
1886 (void)us_saveoptdlog(FALSE);
1887 }
1888 return(gotsaved);
1889 }
1890
1891 /* Prompt: Session Logging */
1892 static DIALOGITEM us_seslogdialogitems[] =
1893 {
1894 /* 1 */ {0, {204,100,228,268}, BUTTON, N_("Save All Information")},
1895 /* 2 */ {0, {240,100,264,268}, BUTTON, N_("Disable Session Logging")},
1896 /* 3 */ {0, {4,4,20,284}, MESSAGE, N_("Warning: not all information has been saved.")},
1897 /* 4 */ {0, {36,4,52,356}, MESSAGE, N_("Unless all libraries and options are saved together")},
1898 /* 5 */ {0, {56,4,72,356}, MESSAGE, N_("It is not possible to reconstruct the session after a crash.")},
1899 /* 6 */ {0, {88,4,104,356}, MESSAGE, N_("The following information has not been saved:")},
1900 /* 7 */ {0, {108,4,192,356}, SCROLL, x_("")}
1901 };
1902 static DIALOG us_seslogdialog = {{75,75,348,441}, N_("Session Logging Warning"), 0, 7, us_seslogdialogitems, 0, 0};
1903
1904 #define DSEL_SAVEALL 1 /* save all information (button) */
1905 #define DSEL_DISLOG 2 /* disable session logging (button) */
1906 #define DSEL_UNSAVED 7 /* what is unsaved (scroll) */
1907
us_continuesessionlogging(void)1908 void us_continuesessionlogging(void)
1909 {
1910 REGISTER BOOLEAN unsaved;
1911 REGISTER void *dia, *infstr;
1912 REGISTER INTBIG itemHit;
1913 REGISTER LIBRARY *lib;
1914
1915 /* if session logging is already off, never mind */
1916 if (us_logrecord == NULL) return;
1917
1918 /* see if there are any unsaved libraries */
1919 unsaved = FALSE;
1920 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1921 {
1922 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
1923 if ((lib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) != 0)
1924 unsaved = TRUE;
1925 }
1926 if (us_optionschanged && optionshavechanged())
1927 unsaved = TRUE;
1928
1929 /* if something is unsaved, prompt the user */
1930 if (unsaved)
1931 {
1932 dia = DiaInitDialog(&us_seslogdialog);
1933 if (dia == 0) return;
1934 DiaInitTextDialog(dia, DSEL_UNSAVED, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, -1, 0);
1935 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1936 {
1937 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
1938 if ((lib->userbits&(LIBCHANGEDMAJOR | LIBCHANGEDMINOR)) == 0) continue;
1939 infstr = initinfstr();
1940 formatinfstr(infstr, x_("Library %s"), lib->libname);
1941 DiaStuffLine(dia, DSEL_UNSAVED, returninfstr(infstr));
1942 }
1943 if (us_optionschanged && optionshavechanged())
1944 DiaStuffLine(dia, DSEL_UNSAVED, _("Options"));
1945 DiaSelectLine(dia, DSEL_UNSAVED, -1);
1946 for(;;)
1947 {
1948 itemHit = DiaNextHit(dia);
1949 if (itemHit == DSEL_SAVEALL || itemHit == DSEL_DISLOG) break;
1950 }
1951 DiaDoneDialog(dia);
1952 if (itemHit == DSEL_DISLOG)
1953 {
1954 /* disable session logging */
1955 logfinishrecord();
1956 return;
1957 }
1958
1959 /* save everything */
1960 (void)us_saveeverything();
1961 }
1962
1963 /* erase everything in the clipboard */
1964 us_clearclipboard();
1965
1966 /* close all modeless dialogs */
1967 DiaCloseAllModeless();
1968
1969 /* truncate the session log */
1970 logfinishrecord();
1971 logstartrecord();
1972 }
1973
1974 /*
1975 * routine to determine the color map entry that corresponds to the string
1976 * "pp". If the string is a number then return that number. If the string
1977 * contains layer letters from the current technology, return that index.
1978 * The value of "purpose" determines how to interpret the layer letters: 0
1979 * means that the letters indicate entries in the color map and 1 means that
1980 * only one letter is allowed and its layer number should be returned. If no
1981 * entry can be determined, the routine issues an error and returns -1.
1982 */
us_getcolormapentry(CHAR * pp,BOOLEAN layerletter)1983 INTBIG us_getcolormapentry(CHAR *pp, BOOLEAN layerletter)
1984 {
1985 CHAR *ch, *pt1;
1986 REGISTER INTBIG color, i, high;
1987 GRAPHICS *desc;
1988
1989 /* first see if the string is all digits and return that value if so */
1990 if (isanumber(pp)) return(myatoi(pp));
1991
1992 /* for layer conversion, the job is simple */
1993 high = el_curtech->layercount;
1994 if (layerletter)
1995 {
1996 if (pp[0] == 0 || pp[1] != 0)
1997 {
1998 us_abortcommand(_("Can only give one layer letter"));
1999 return(-1);
2000 }
2001 for(i=0; i<high; i++)
2002 {
2003 for(ch = us_layerletters(el_curtech, i); *ch != 0; ch++)
2004 if (*ch == pp[0]) return(i);
2005 }
2006 us_abortcommand(_("Letter '%s' is not a valid layer"), pp);
2007 return(-1);
2008 }
2009
2010 /* accumulate the desired color */
2011 color = 0;
2012 for(pt1 = pp; *pt1 != 0; pt1++)
2013 {
2014 /* find the layer that corresponds to letter "*pt1" */
2015 for(i=0; i<high; i++)
2016 {
2017 /* see if this layer has the right letter */
2018 for(ch = us_layerletters(el_curtech, i); *ch != 0; ch++)
2019 if (*ch == *pt1) break;
2020 if (*ch == 0) continue;
2021
2022 /* get the color characteristics of this layer */
2023 desc = el_curtech->layers[i];
2024 if ((desc->bits & color) != 0)
2025 {
2026 us_abortcommand(_("No single color for the letters '%s'"), pp);
2027 return(-1);
2028 }
2029 color |= desc->col;
2030 break;
2031 }
2032 if (i == high)
2033 {
2034 us_abortcommand(_("Letter '%c' is not a valid layer"), *pt1);
2035 return(-1);
2036 }
2037 }
2038 return(color);
2039 }
2040
2041 /*
2042 * routine to return a unique port prototype name in cell "cell" given that
2043 * a new prototype wants to be named "name". The routine allocates space
2044 * for the string that is returned so this must be freed when done.
2045 */
us_uniqueportname(CHAR * name,NODEPROTO * cell)2046 CHAR *us_uniqueportname(CHAR *name, NODEPROTO *cell)
2047 {
2048 CHAR *str;
2049
2050 str = us_uniqueobjectname(name, cell, VPORTPROTO, 0);
2051
2052 if (us_uniqueretstr != NOSTRING) efree(us_uniqueretstr);
2053 (void)allocstring(&us_uniqueretstr, str, us_tool->cluster);
2054 return(us_uniqueretstr);
2055 }
2056
2057 /*
2058 * Routine to determine whether the name "name" is unique in cell "cell"
2059 * (given that it is on objects of type "type"). Does not consider object
2060 * "exclude" (if nonzero).
2061 */
us_isuniquename(CHAR * name,NODEPROTO * cell,INTBIG type,void * exclude)2062 BOOLEAN us_isuniquename(CHAR *name, NODEPROTO *cell, INTBIG type, void *exclude)
2063 {
2064 REGISTER PORTPROTO *pp;
2065 REGISTER ARCINST *ai;
2066 REGISTER NODEINST *ni;
2067 REGISTER VARIABLE *var;
2068
2069 switch (type)
2070 {
2071 case VPORTPROTO:
2072 pp = getportproto(cell, name);
2073 if (pp == NOPORTPROTO) break;
2074 if (exclude != 0 && (PORTPROTO *)exclude == pp) break;
2075 return(FALSE);
2076 case VNODEINST:
2077 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2078 {
2079 if (exclude != 0 && (NODEINST *)exclude == ni) continue;
2080 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
2081 if (var == NOVARIABLE) continue;
2082 if (namesame(name, (CHAR *)var->addr) == 0) return(FALSE);
2083 }
2084 break;
2085 case VARCINST:
2086 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2087 {
2088 if (exclude != 0 && (ARCINST *)exclude == ai) continue;
2089 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
2090 if (var == NOVARIABLE) continue;
2091 if (namesame(name, (CHAR *)var->addr) == 0) return(FALSE);
2092 }
2093 break;
2094 }
2095 return(TRUE);
2096 }
2097
2098 /*
2099 * routine to return a unique object name in cell "cell" starting with the
2100 * name "name".
2101 */
us_uniqueobjectname(CHAR * name,NODEPROTO * cell,INTBIG type,void * exclude)2102 CHAR *us_uniqueobjectname(CHAR *name, NODEPROTO *cell, INTBIG type, void *exclude)
2103 {
2104 CHAR *newname, separatestring[2];
2105 REGISTER INTBIG nextindex, i, possiblestart, possibleend, startindex, endindex, spacing,
2106 endpos, startpos;
2107 BOOLEAN foundnumbers;
2108 REGISTER void *infstr;
2109
2110 /* first see if the name is unique */
2111 if (us_isuniquename(name, cell, type, exclude)) return(name);
2112
2113 /* now see if the name ends in "]" */
2114 i = estrlen(name);
2115 if (name[i-1] == ']')
2116 {
2117 /* see if the array contents can be incremented */
2118 possiblestart = -1;
2119 endpos = i-1;
2120 for(;;)
2121 {
2122 /* find the range of characters in square brackets */
2123 for(startpos = endpos; startpos >= 0; startpos--)
2124 if (name[startpos] == '[') break;
2125 if (name[startpos] != '[') break;
2126
2127 /* see if there is a comma in the bracketed expression */
2128 for(i=startpos+1; i<endpos; i++)
2129 if (name[i] == ',') break;
2130 if (name[i] == ',')
2131 {
2132 /* this bracketed expression cannot be incremented: move on */
2133 if (startpos > 0 && name[startpos-1] == ']')
2134 {
2135 endpos = startpos-1;
2136 continue;
2137 }
2138 break;
2139 }
2140
2141 /* see if there is a colon in the bracketed expression */
2142 for(i=startpos+1; i<endpos; i++)
2143 if (name[i] == ':') break;
2144 if (name[i] == ':')
2145 {
2146 /* colon: make sure there are two numbers */
2147 name[i] = 0;
2148 name[endpos] = 0;
2149 foundnumbers = isanumber(&name[startpos+1]) && isanumber(&name[i+1]);
2150 name[i] = ':';
2151 name[endpos] = ']';
2152 if (foundnumbers)
2153 {
2154 startindex = atoi(&name[startpos+1]);
2155 endindex = atoi(&name[i+1]);
2156 spacing = abs(endindex - startindex) + 1;
2157 for(nextindex = 1; ; nextindex++)
2158 {
2159 infstr = initinfstr();
2160 for(i=0; i<startpos; i++) addtoinfstr(infstr, name[i]);
2161 formatinfstr(infstr, x_("[%ld:%ld"), startindex+spacing*nextindex,
2162 endindex+spacing*nextindex);
2163 addstringtoinfstr(infstr, &name[endpos]);
2164 newname = returninfstr(infstr);
2165 if (us_isuniquename(newname, cell, type, 0)) break;
2166 }
2167 return(newname);
2168 }
2169
2170 /* this bracketed expression cannot be incremented: move on */
2171 if (startpos > 0 && name[startpos-1] == ']')
2172 {
2173 endpos = startpos-1;
2174 continue;
2175 }
2176 break;
2177 }
2178
2179 /* see if this bracketed expression is a pure number */
2180 name[endpos] = 0;
2181 foundnumbers = isanumber(&name[startpos+1]);
2182 name[endpos] = ']';
2183 if (foundnumbers)
2184 {
2185 nextindex = myatoi(&name[startpos+1]) + 1;
2186 for(; ; nextindex++)
2187 {
2188 infstr = initinfstr();
2189 for(i=0; i<startpos; i++) addtoinfstr(infstr, name[i]);
2190 formatinfstr(infstr, x_("[%ld"), nextindex);
2191 addstringtoinfstr(infstr, &name[endpos]);
2192 newname = returninfstr(infstr);
2193 if (us_isuniquename(newname, cell, type, 0)) break;
2194 }
2195 return(newname);
2196 }
2197
2198 /* remember the first index that could be incremented in a pinch */
2199 if (possiblestart < 0)
2200 {
2201 possiblestart = startpos;
2202 possibleend = endpos;
2203 }
2204
2205 /* this bracketed expression cannot be incremented: move on */
2206 if (startpos > 0 && name[startpos-1] == ']')
2207 {
2208 endpos = startpos-1;
2209 continue;
2210 }
2211 break;
2212 }
2213
2214 /* if there was a possible place to increment, do it */
2215 if (possiblestart >= 0)
2216 {
2217 /* nothing simple, but this one can be incremented */
2218 for(i=possibleend-1; i>possiblestart; i--)
2219 if (!isdigit(name[i])) break;
2220 nextindex = myatoi(&name[i+1]) + 1;
2221 startpos = i+1;
2222 if (name[startpos-1] == us_separatechar) startpos--;
2223 for(; ; nextindex++)
2224 {
2225 infstr = initinfstr();
2226 for(i=0; i<startpos; i++) addtoinfstr(infstr, name[i]);
2227 formatinfstr(infstr, x_("%c%ld"), us_separatechar, nextindex);
2228 addstringtoinfstr(infstr, &name[possibleend]);
2229 newname = returninfstr(infstr);
2230 if (us_isuniquename(newname, cell, type, 0)) break;
2231 }
2232 return(newname);
2233 }
2234 }
2235
2236 /* array contents cannot be incremented: increment base name */
2237 for(startpos=0; name[startpos] != 0; startpos++)
2238 if (name[startpos] == '[') break;
2239 endpos = startpos;
2240
2241 /* if there is a numeric part at the end, increment that */
2242 separatestring[0] = (CHAR)us_separatechar;
2243 separatestring[1] = 0;
2244 while (startpos > 0 && isdigit(name[startpos-1])) startpos--;
2245 if (startpos >= endpos)
2246 {
2247 nextindex = 1;
2248 if (startpos > 0 && name[startpos-1] == us_separatechar) startpos--;
2249 } else
2250 {
2251 nextindex = myatoi(&name[startpos]) + 1;
2252 separatestring[0] = 0;
2253 }
2254
2255 for(; ; nextindex++)
2256 {
2257 infstr = initinfstr();
2258 for(i=0; i<startpos; i++) addtoinfstr(infstr, name[i]);
2259 formatinfstr(infstr, x_("%s%ld"), separatestring, nextindex);
2260 addstringtoinfstr(infstr, &name[endpos]);
2261 newname = returninfstr(infstr);
2262 if (us_isuniquename(newname, cell, type, 0)) break;
2263 }
2264 return(newname);
2265 }
2266
2267 /*
2268 * routine to initialize the database variable "USER_layer_letters". This
2269 * is called once at initialization and again whenever the array is changed.
2270 */
us_initlayerletters(void)2271 void us_initlayerletters(void)
2272 {
2273 REGISTER VARIABLE *var;
2274 REGISTER TECHNOLOGY *t;
2275
2276 if (us_layer_letter_data != 0) efree((CHAR *)us_layer_letter_data);
2277 us_layer_letter_data = emalloc((el_maxtech * SIZEOFINTBIG), us_tool->cluster);
2278 if (us_layer_letter_data == 0) return;
2279 for(t = el_technologies; t != NOTECHNOLOGY; t = t->nexttechnology)
2280 {
2281 var = getvalkey((INTBIG)t, VTECHNOLOGY, VSTRING|VISARRAY, us_layer_letters_key);
2282 us_layer_letter_data[t->techindex] = (var == NOVARIABLE ? 0 : var->addr);
2283 }
2284 }
2285
2286 /*
2287 * routine to return a string of unique letters describing layer "layer"
2288 * in technology "tech". The letters for all layers of a given technology
2289 * must not intersect. This routine accesses the "USER_layer_letters"
2290 * variable on the technology objects.
2291 */
us_layerletters(TECHNOLOGY * tech,INTBIG layer)2292 CHAR *us_layerletters(TECHNOLOGY *tech, INTBIG layer)
2293 {
2294 REGISTER INTBIG addr;
2295
2296 if (us_layer_letter_data == 0)
2297 {
2298 us_initlayerletters();
2299 if (us_layer_letter_data == 0) return(x_(""));
2300 }
2301
2302 addr = us_layer_letter_data[tech->techindex];
2303 if (addr == 0) return(x_(""));
2304 return(((CHAR **)addr)[layer]);
2305 }
2306
2307 /*
2308 * routine to change an tool state. The name of the tool is in "pt" (if "pt" is
2309 * null then an tool name is prompted). The state of the tool is set to "state"
2310 * (0 for off, 1 for permanently off, 2 for on).
2311 */
us_settool(INTBIG count,CHAR * par[],INTBIG state)2312 void us_settool(INTBIG count, CHAR *par[], INTBIG state)
2313 {
2314 REGISTER INTBIG i;
2315 BOOLEAN toolstate;
2316 REGISTER CHAR *pt;
2317 extern COMCOMP us_onofftoolp;
2318 REGISTER TOOL *tool;
2319
2320 if (count == 0)
2321 {
2322 count = ttygetparam(M_("Which tool: "), &us_onofftoolp, MAXPARS, par);
2323 if (count == 0)
2324 {
2325 us_abortcommand(M_("Specify an tool to control"));
2326 return;
2327 }
2328 }
2329 pt = par[0];
2330
2331 for(i=0; i<el_maxtools; i++)
2332 if (namesame(el_tools[i].toolname, pt) == 0) break;
2333 if (i >= el_maxtools)
2334 {
2335 us_abortcommand(_("No tool called %s"), pt);
2336 return;
2337 }
2338 tool = &el_tools[i];
2339
2340 if (tool == us_tool && state <= 1)
2341 {
2342 us_abortcommand(M_("No! I won't go!"));
2343 return;
2344 }
2345 if ((tool->toolstate&TOOLON) == 0 && state <= 1)
2346 {
2347 ttyputverbose(M_("%s already off"), pt);
2348 return;
2349 }
2350 if ((tool->toolstate&TOOLON) != 0 && state > 1)
2351 {
2352 ttyputverbose(M_("%s already on"), pt);
2353 return;
2354 }
2355
2356 if (state <= 1)
2357 {
2358 ttyputverbose(M_("%s turned off"), tool->toolname);
2359 if (state != 0) toolstate = TRUE; else
2360 toolstate = FALSE;
2361 toolturnoff(tool, toolstate);
2362 } else
2363 {
2364 if ((tool->toolstate&TOOLINCREMENTAL) == 0)
2365 ttyputverbose(M_("%s turned on"), tool->toolname); else
2366 ttyputmsg(_("%s turned on, catching up on changes"), tool->toolname);
2367 toolturnon(tool);
2368 }
2369 }
2370