1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrgraph.c
6 * User interface tool: structure graphing module
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 "tecgen.h"
36 #include "tecart.h"
37
38 /****************************** LIBRARY GRAPHING *****************************/
39
40 #define NONODEDESCR ((NODEDESCR *)-1)
41
42 typedef struct Inodedescr
43 {
44 INTBIG x, y;
45 INTBIG yoff;
46 NODEINST *pin;
47 struct Inodedescr *main;
48 } NODEDESCR;
49
50 static NODEPROTO *us_graphmainview(NODEPROTO *np);
51
us_graphcells(NODEPROTO * top)52 void us_graphcells(NODEPROTO *top)
53 {
54 REGISTER NODEPROTO *np, *sub, *graphnp, *truenp, *truesubnp;
55 REGISTER NODEINST *ni, *nibot, *toppin;
56 REGISTER ARCINST *ai;
57 REGISTER LIBRARY *lib;
58 REGISTER INTBIG more, maxdepth, color;
59 REGISTER INTBIG *xval, *yoff, i, x, y, xe, ye, clock, maxwidth, xsc, lambda, xscale, yscale, yoffset;
60 REGISTER PORTPROTO *pinpp;
61 REGISTER VARIABLE *var;
62 REGISTER NODEDESCR *nd, *ndsub;
63 CHAR *newname;
64 float spread;
65 REGISTER void *infstr;
66
67 pinpp = gen_invispinprim->firstportproto;
68
69 /* create the graph cell */
70 graphnp = newnodeproto(x_("CellStructure"), el_curlib);
71 if (graphnp == NONODEPROTO) return;
72 if (graphnp->prevversion != NONODEPROTO)
73 ttyputverbose(M_("Creating new version of cell: CellStructure")); else
74 ttyputverbose(M_("Creating cell: CellStructure"));
75
76 /* clear flags on all of the cells */
77 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
78 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
79 np->temp1 = -1;
80
81 /* find all top-level cells */
82 if (top != NONODEPROTO) top->temp1 = 0; else
83 {
84 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
85 {
86 if (np->firstinst == NONODEINST) np->temp1 = 0;
87 }
88 }
89
90 /* now place all cells at their proper depth */
91 maxdepth = 0;
92 more = 1;
93 while (more != 0)
94 {
95 more = 0;
96 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
97 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
98 {
99 if (np->temp1 == -1) continue;
100 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
101 {
102 sub = ni->proto;
103 if (sub->primindex != 0) continue;
104
105 /* ignore recursive references (showing icon in contents) */
106 if (isiconof(sub, np)) continue;
107 if (sub->temp1 <= np->temp1)
108 {
109 sub->temp1 = np->temp1 + 1;
110 if (sub->temp1 > maxdepth) maxdepth = sub->temp1;
111 more++;
112 }
113 truenp = contentsview(ni->proto);
114 if (truenp == NONODEPROTO) continue;
115 if (truenp->temp1 <= np->temp1)
116 {
117 truenp->temp1 = np->temp1 + 1;
118 if (truenp->temp1 > maxdepth) maxdepth = truenp->temp1;
119 more++;
120 }
121 }
122 }
123
124 /* add in any cells referenced from other libraries */
125 if (more == 0 && top == NONODEPROTO)
126 {
127 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
128 {
129 if (np->temp1 >= 0) continue;
130 np->temp1 = 0;
131 more++;
132 }
133 }
134 }
135
136 /* now assign X coordinates to each cell */
137 maxdepth++;
138 maxwidth = 0;
139 xval = emalloc((SIZEOFINTBIG * maxdepth), el_tempcluster);
140 if (xval == 0) return;
141 yoff = emalloc((SIZEOFINTBIG * maxdepth), el_tempcluster);
142 if (yoff == 0) return;
143 for(i=0; i<maxdepth; i++) xval[i] = yoff[i] = 0;
144 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
145 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
146 {
147 /* ignore icon cells from the graph (merge with contents) */
148 if (np->temp1 == -1) continue;
149
150 /* ignore associated cells for now */
151 truenp = us_graphmainview(np);
152 if (truenp != NONODEPROTO &&
153 (np->firstnodeinst == NONODEINST || np->cellview == el_iconview ||
154 np->cellview == el_skeletonview))
155 {
156 np->temp1 = -1;
157 continue;
158 }
159
160 nd = (NODEDESCR *)emalloc(sizeof (NODEDESCR), us_tool->cluster);
161 nd->pin = NONODEINST;
162 nd->main = NONODEDESCR;
163
164 nd->x = xval[np->temp1];
165 xval[np->temp1] += estrlen(describenodeproto(np));
166 if (xval[np->temp1] > maxwidth) maxwidth = xval[np->temp1];
167 nd->y = np->temp1;
168 nd->yoff = 0;
169 np->temp1 = (INTBIG)nd;
170 }
171
172 /* now center each row */
173 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
174 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
175 {
176 if (np->temp1 == -1) continue;
177 nd = (NODEDESCR *)np->temp1;
178 if (xval[nd->y] < maxwidth)
179 {
180 spread = (float)maxwidth / (float)xval[nd->y];
181 nd->x = roundfloat(nd->x * spread);
182 }
183 }
184
185 /* generate accurate X/Y coordinates */
186 lambda = el_curlib->lambda[art_tech->techindex];
187 xscale = lambda * 2 / 3;
188 yscale = lambda * 20;
189 yoffset = lambda/2;
190 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
191 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
192 {
193 if (np->temp1 == -1) continue;
194 nd = (NODEDESCR *)np->temp1;
195 x = nd->x; y = nd->y;
196 x = x * xscale;
197 y = -y * yscale + ((yoff[nd->y]++)%2) * yoffset;
198 nd->x = x; nd->y = y;
199 }
200
201 /* make unattached cells sit with their contents view */
202 if (top == NONODEPROTO)
203 {
204 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
205 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
206 {
207 if (np->temp1 != -1) continue;
208 if (np->firstnodeinst != NONODEINST && np->cellview != el_iconview &&
209 np->cellview != el_skeletonview) continue;
210 truenp = us_graphmainview(np);
211 if (truenp == NONODEPROTO) continue;
212 if (truenp->temp1 == -1) continue;
213
214 nd = (NODEDESCR *)truenp->temp1;
215 ndsub = (NODEDESCR *)emalloc(sizeof (NODEDESCR), us_tool->cluster);
216 ndsub->pin = NONODEINST;
217 ndsub->main = nd;
218 nd->yoff += yoffset*2;
219 ndsub->x = nd->x; ndsub->y = nd->y + nd->yoff;
220 np->temp1 = (INTBIG)ndsub;
221 }
222 }
223
224 /* write the header message */
225 xsc = maxwidth * xscale / 2;
226 ni = newnodeinst(gen_invispinprim, xsc, xsc, yscale, yscale, 0, 0, graphnp);
227 if (ni == NONODEINST) return;
228 endobjectchange((INTBIG)ni, VNODEINST);
229 infstr = initinfstr();
230 if (top != NONODEPROTO)
231 {
232 formatinfstr(infstr, _("Structure below cell %s"), describenodeproto(top));
233 } else
234 {
235 formatinfstr(infstr, _("Structure of library %s"), el_curlib->libname);
236 }
237 allocstring(&newname, returninfstr(infstr), el_tempcluster);
238 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)newname, VSTRING|VDISPLAY);
239 efree(newname);
240 if (var != NOVARIABLE)
241 TDSETSIZE(var->textdescript, TXTSETQLAMBDA(24));
242
243 /* place the components */
244 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
245 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
246 {
247 if (np == graphnp) continue;
248 if (np->temp1 == -1) continue;
249 nd = (NODEDESCR *)np->temp1;
250
251 x = nd->x; y = nd->y;
252 ni = newnodeinst(gen_invispinprim, x, x, y, y, 0, 0, graphnp);
253 if (ni == NONODEINST) return;
254 endobjectchange((INTBIG)ni, VNODEINST);
255 nd->pin = ni;
256
257 /* write the cell name in the node */
258 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)describenodeproto(np),
259 VSTRING|VDISPLAY);
260 if (var != NOVARIABLE)
261 TDSETSIZE(var->textdescript, TXTSETQLAMBDA(4));
262 }
263
264 /* attach related components with rigid arcs */
265 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
266 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
267 {
268 if (np == graphnp) continue;
269 if (np->temp1 == -1) continue;
270 nd = (NODEDESCR *)np->temp1;
271 if (nd->main == NONODEDESCR) continue;
272
273 ai = newarcinst(art_solidarc, 0, FIXED, nd->pin, pinpp, nd->x, nd->y,
274 nd->main->pin, pinpp, nd->main->x, nd->main->y, graphnp);
275 if (ai == NOARCINST) return;
276 endobjectchange((INTBIG)ai, VARCINST);
277
278 /* set an invisible color on the arc */
279 (void)setvalkey((INTBIG)ai, VARCINST, art_colorkey, 0, VINTEGER);
280 }
281
282 /* build wires between the hierarchical levels */
283 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
284 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
285 np->temp2 = 0;
286 clock = 0;
287 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
288 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
289 {
290 if (np == graphnp) continue;
291
292 /* always use the contents cell, not the icon */
293 truenp = contentsview(np);
294 if (truenp == NONODEPROTO) truenp = np;
295 if (truenp->temp1 == -1) continue;
296
297 nd = (NODEDESCR *)truenp->temp1;
298 toppin = NONODEINST;
299 clock++;
300 for(ni = truenp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
301 {
302 sub = ni->proto;
303 if (sub->primindex != 0) continue;
304
305 /* ignore recursive references (showing icon in contents) */
306 if (isiconof(sub, truenp)) continue;
307
308 truesubnp = contentsview(sub);
309 if (truesubnp == NONODEPROTO) truesubnp = sub;
310
311 if (truesubnp->temp2 == clock) continue;
312 truesubnp->temp2 = clock;
313
314 /* draw a line from cell "truenp" to cell "truesubnp" */
315 x = nd->x;
316 y = nd->y;
317
318 if (truesubnp->temp1 == -1) continue;
319 ndsub = (NODEDESCR *)truesubnp->temp1;
320 xe = ndsub->x;
321 ye = ndsub->y;
322 toppin = nd->pin;
323 nibot = ndsub->pin;
324 ai = newarcinst(art_solidarc, defaultarcwidth(art_solidarc), 0, toppin,
325 pinpp, x, y, nibot, pinpp, xe, ye, graphnp);
326 if (ai == NOARCINST) return;
327 endobjectchange((INTBIG)ai, VARCINST);
328
329 /* set an appropriate color on the arc (red for jumps of more than 1 level of depth) */
330 color = BLUE;
331 if (nd->y - ndsub->y > yscale+yoffset+yoffset) color = RED;
332 (void)setvalkey((INTBIG)ai, VARCINST, art_colorkey, color, VINTEGER);
333 }
334 }
335
336 /* free space */
337 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
338 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
339 {
340 if (np->temp1 == -1) continue;
341 efree((CHAR *)np->temp1);
342 }
343 efree((CHAR *)xval);
344 efree((CHAR *)yoff);
345 }
346
347 /*
348 * routine to find the main cell that "np" is associated with in the graph. This code is
349 * essentially the same as "contentscell()" except that any original type is allowed.
350 * Returns NONODEPROTO if the cell is not associated.
351 */
us_graphmainview(NODEPROTO * np)352 NODEPROTO *us_graphmainview(NODEPROTO *np)
353 {
354 REGISTER NODEPROTO *rnp;
355
356 /* primitives have no contents view */
357 if (np == NONODEPROTO) return(NONODEPROTO);
358 if (np->primindex != 0) return(NONODEPROTO);
359
360 /* first check to see if there is a schematics link */
361 FOR_CELLGROUP(rnp, np)
362 {
363 if (rnp->cellview == el_schematicview) return(rnp);
364 if ((rnp->cellview->viewstate&MULTIPAGEVIEW) != 0) return(rnp);
365 }
366
367 /* now check to see if there is any layout link */
368 FOR_CELLGROUP(rnp, np)
369 if (rnp->cellview == el_layoutview) return(rnp);
370
371 /* finally check to see if there is any "unknown" link */
372 FOR_CELLGROUP(rnp, np)
373 if (rnp->cellview == el_unknownview) return(rnp);
374
375 /* no contents found */
376 return(NONODEPROTO);
377 }
378
379 /****************************** COMMAND GRAPHING ******************************/
380
381 #define MAXILLUSTRATEDEPTH 100 /* maximum depth of command graph */
382 #define FORCEDDEPTH 7 /* required depth of command graph */
383 #define MAXILLUSTRATEWIDTH 200 /* maximum depth of command graph */
384 #define XCOMSCALE 1000 /* horizontal distance between words */
385 #define YCOMSCALE (-10000) /* vertical distance between words */
386 #define YCOMOFFSET 1000 /* vertical offset between words */
387
388 #define NOCOMILL ((COMILL *)-1)
389
390 typedef struct Icomill
391 {
392 CHAR *name;
393 INTBIG x, y;
394 INTBIG realx;
395 INTBIG children;
396 INTBIG depth;
397 struct Icomill *parent;
398 struct Icomill *nextcomill;
399 NODEINST *real;
400 } COMILL;
401
402 static COMILL *us_comilllist[MAXILLUSTRATEWIDTH];
403 static COMILL *us_allcomill;
404
405 static INTBIG us_maxillustratedepth, us_maxcommandentries;
406 static INTBIG us_illustrateXpos[MAXILLUSTRATEDEPTH]; /* current build-out X position */
407 static COMCOMP *us_illustrateparam[MAXILLUSTRATEDEPTH]; /* current parameter type */
408
409 /* prototypes for local routines */
410 static COMILL *us_illustratecommand(CHAR*, INTBIG, COMILL*);
411
us_illustratecommandset(void)412 void us_illustratecommandset(void)
413 {
414 REGISTER INTBIG i;
415 REGISTER INTBIG j;
416 CHAR *newmessage[1];
417 REGISTER NODEPROTO *graphnp;
418 REGISTER NODEINST *ni;
419 REGISTER COMILL *ci, *nextci;
420 INTBIG xs, ys, xe, ye;
421 REGISTER ARCINST *ai;
422 REGISTER VARIABLE *var;
423
424 /* create the graph cell */
425 graphnp = newnodeproto(x_("CommandStructure"), el_curlib);
426 if (graphnp == NONODEPROTO) return;
427 if (graphnp->prevversion != NONODEPROTO)
428 ttyputmsg(_("Creating new version of cell: CommandStructure")); else
429 ttyputmsg(_("Creating cell: CommandStructure"));
430
431 us_maxillustratedepth = 0;
432 us_maxcommandentries = 0;
433 for(i = 0; i < MAXILLUSTRATEDEPTH; i++) us_illustrateXpos[i] = 0;
434 for(i = 0; i < MAXILLUSTRATEWIDTH; i++) us_comilllist[i] = NOCOMILL;
435 us_allcomill = NOCOMILL;
436
437 /* build the command graph */
438 for(i = 0; us_lcommand[i].name != 0; i++)
439 {
440 for(j=0; j<us_lcommand[i].params; j++)
441 us_illustrateparam[j] = us_lcommand[i].par[j];
442 us_illustrateparam[us_lcommand[i].params] = NOCOMCOMP;
443 us_comilllist[i] = us_illustratecommand(us_lcommand[i].name, 0, NOCOMILL);
444 }
445
446 ttyputmsg(_("%ld entries in command graph"), us_maxcommandentries);
447
448 /* count the breadth information */
449 j = 0;
450 for(i = 0; i < us_maxillustratedepth; i++)
451 if (us_illustrateXpos[i] > j) j = us_illustrateXpos[i];
452
453 /* write the header message */
454 ni = newnodeinst(gen_invispinprim, 0, j, -YCOMSCALE,
455 gen_invispinprim->highx-gen_invispinprim->lowx-YCOMSCALE, 0, 0, graphnp);
456 if (ni == NONODEINST) return;
457 endobjectchange((INTBIG)ni, VNODEINST);
458 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)_("Structure of commands"),
459 VSTRING|VDISPLAY);
460 if (var != NOVARIABLE)
461 TDSETSIZE(var->textdescript, TXTSETPOINTS(20));
462
463 /* make the name spacing uniform */
464 for(ci = us_allcomill; ci != NOCOMILL; ci = ci->nextcomill)
465 ci->realx = ci->children = 0;
466 for(i = us_maxillustratedepth-1; i > 0; i--)
467 {
468 for(ci = us_allcomill; ci != NOCOMILL; ci = ci->nextcomill)
469 {
470 if (ci->depth != i) continue;
471 ci->parent->realx += ci->x;
472 ci->parent->children++;
473 }
474 for(ci = us_allcomill; ci != NOCOMILL; ci = ci->nextcomill)
475 if (ci->depth == i-1 && ci->children != 0)
476 ci->x = ci->realx / ci->children;
477 }
478
479 /* now place the names */
480 for(ci = us_allcomill; ci != NOCOMILL; ci = ci->nextcomill)
481 {
482 if (ci->name == 0) continue;
483 ni = newnodeinst(gen_invispinprim, ci->x,
484 ci->x+gen_invispinprim->highx-gen_invispinprim->lowx, ci->y,
485 ci->y+gen_invispinprim->highy-gen_invispinprim->lowy, 0, 0, graphnp);
486 if (ni == NONODEINST) return;
487 endobjectchange((INTBIG)ni, VNODEINST);
488 ci->real = ni;
489
490 /* set the node name, color, font */
491 var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)ci->name, VSTRING|VDISPLAY);
492 if (var != NOVARIABLE)
493 defaulttextsize(2, var->textdescript);
494 (void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, RED, VINTEGER);
495 }
496
497 /* connect the names with arcs */
498 for(ci = us_allcomill; ci != NOCOMILL; ci = ci->nextcomill)
499 {
500 if (ci->name == 0) continue;
501 if (ci->parent == NOCOMILL) continue;
502 portposition(ci->real, ci->real->proto->firstportproto, &xs, &ys);
503 portposition(ci->parent->real, ci->parent->real->proto->firstportproto, &xe, &ye);
504 ai = newarcinst(gen_universalarc, defaultarcwidth(gen_universalarc), 0, ci->real,
505 ci->real->proto->firstportproto, xs, ys, ci->parent->real,
506 ci->parent->real->proto->firstportproto, xe, ye, graphnp);
507 if (ai == NOARCINST) break;
508 endobjectchange((INTBIG)ai, VARCINST);
509 }
510
511 /* delete it all */
512 for(ci = us_allcomill; ci != NOCOMILL; ci = nextci)
513 {
514 nextci = ci->nextcomill;
515 efree((CHAR *)ci);
516 }
517
518 /* have the cell displayed on the screen */
519 newmessage[0] = x_("CommandStructure");
520 us_editcell(1, newmessage);
521 }
522
us_illustratecommand(CHAR * name,INTBIG depth,COMILL * thisci)523 COMILL *us_illustratecommand(CHAR *name, INTBIG depth, COMILL *thisci)
524 {
525 static COMCOMP us_recursioncomcomp = {
526 NOKEYWORD, NOTOPLIST, NONEXTLIST, NOPARAMS, 0, x_(""), x_("")};
527 REGISTER COMCOMP *cc;
528 REGISTER COMILL *ci, *subci;
529 REGISTER INTBIG i, j, k;
530 REGISTER CHAR *arg;
531
532 /* put this name at the appropriate depth */
533 if (depth >= MAXILLUSTRATEDEPTH) return(NOCOMILL);
534 if (depth > us_maxillustratedepth) us_maxillustratedepth = depth;
535
536 ci = (COMILL *)emalloc(sizeof (COMILL), el_tempcluster);
537 if (ci == 0) return(NOCOMILL);
538 ci->name = name;
539 ci->depth = depth;
540 ci->parent = thisci;
541 ci->nextcomill = us_allcomill;
542 us_allcomill = ci;
543 ci->x = us_illustrateXpos[depth];
544 ci->y = ci->depth * YCOMSCALE + ((us_illustrateXpos[depth]/XCOMSCALE)%5-2) * YCOMOFFSET;
545 us_illustrateXpos[depth] += XCOMSCALE;
546 if (name != 0) us_maxcommandentries++;
547
548 /* if there is nothing below this command, return now */
549 if (name == 0 || us_illustrateparam[depth] == NOCOMCOMP)
550 {
551 /* force extension of the tree to a specified depth */
552 if (depth < FORCEDDEPTH)
553 (void)us_illustratecommand((CHAR *)0, depth+1, ci);
554 return(ci);
555 }
556
557 cc = us_illustrateparam[depth];
558 if (cc->ifmatch == NOKEYWORD)
559 {
560 if (cc->toplist == topoffile) arg = x_("FILE"); else
561 if (cc->toplist == topoflibfile) arg = x_("LIBRARY"); else
562 if (cc->toplist == topoftechs) arg = x_("TECH"); else
563 if (cc->toplist == topoflibs) arg = x_("LIB"); else
564 if (cc->toplist == topoftools) arg = x_("TOOL"); else
565 if (cc->toplist == topofviews) arg = x_("VIEW"); else
566 if (cc->toplist == topofnets) arg = x_("NET"); else
567 if (cc->toplist == topofarcs) arg = x_("ARC"); else
568 if (cc->toplist == topofcells) arg = x_("CELL"); else
569 if (cc->toplist == us_topofcommands) arg = x_("COM"); else
570 if (cc->toplist == us_topofmacros) arg = x_("MACRO"); else
571 if (cc->toplist == us_topofpopupmenu) arg = x_("POPUP"); else
572 if (cc->toplist == us_topofports) arg = x_("PORT"); else
573 if (cc->toplist == us_topofcports) arg = x_("CELLPORT"); else
574 if (cc->toplist == us_topofexpports) arg = x_("EXPORT"); else
575 if (cc->toplist == us_topofwindows) arg = x_("WINDOWPART"); else
576 if (cc->toplist == us_topoflayers) arg = x_("LAYER"); else
577 if (cc->toplist == us_topofhighlight) arg = x_("HIGH"); else
578 if (cc->toplist == us_topofarcnodes) arg = x_("ARC/NODE"); else
579 if (cc->toplist == us_topofnodes) arg = x_("NODE"); else
580 if (cc->toplist == us_topofcells) arg = x_("CELL"); else
581 if (cc->toplist == us_topofprims) arg = x_("PRIM"); else
582 if (cc->toplist == us_topofconstraints) arg = x_("CONSTR"); else
583 if (cc->toplist == us_topofmbuttons) arg = x_("BUTTON"); else
584 if (cc->toplist == us_topofedteclay) arg = x_("LAYER"); else
585 if (cc->toplist == us_topofedtecarc) arg = x_("ARC"); else
586 if (cc->toplist == us_topofedtecnode) arg = x_("NODE"); else
587 if (cc->toplist == us_topofallthings) arg = x_("ANY"); else
588 if (cc->toplist == us_topofvars) arg = x_("VAR"); else
589 if (cc == &us_recursioncomcomp) arg = x_("***"); else arg = x_("ARG");
590 subci = us_illustratecommand(arg, depth+1, ci);
591 if (subci == NOCOMILL) return(NOCOMILL);
592 return(ci);
593 }
594
595 for(i=0; cc->ifmatch[i].name != 0; i++)
596 {
597 /* spread open the list and insert these options */
598 k = cc->ifmatch[i].params;
599 for(j = MAXILLUSTRATEDEPTH-k-2; j >= depth; j--)
600 us_illustrateparam[j+k+1] = us_illustrateparam[j+1];
601 for(j = 0; j < k; j++)
602 {
603 us_illustrateparam[depth+j+1] = cc->ifmatch[i].par[j];
604 if (us_illustrateparam[depth+j+1] != us_illustrateparam[depth]) continue;
605 us_illustrateparam[depth+j+1] = &us_recursioncomcomp;
606 }
607
608 subci = us_illustratecommand(cc->ifmatch[i].name, depth+1, ci);
609 if (subci == NOCOMILL) return(NOCOMILL);
610
611 /* remove the inserted options */
612 for(j=depth+1; j<MAXILLUSTRATEDEPTH-k; j++)
613 us_illustrateparam[j] = us_illustrateparam[j+k];
614 }
615 return(ci);
616 }
617
618 /****************************** PULLDOWN MENU DUMPING ******************************/
619
620 /* prototypes for local routines */
621 static void us_dumppulldownmenu(FILE *io, POPUPMENU *pm, CHAR *name, CHAR *prefix);
622
623 /*
624 * Routine to dump the pulldown menus to an indented text file.
625 */
us_dumppulldownmenus(void)626 void us_dumppulldownmenus(void)
627 {
628 FILE *io;
629 CHAR *truename;
630 REGISTER INTBIG i;
631 REGISTER POPUPMENU *pm;
632
633 io = xcreate(x_("pulldowns.txt"), el_filetypetext, M_("Menu dump file"), &truename);
634 if (io == NULL) return;
635
636 xprintf(io, M_("Pulldown menus in Electric as of %s\n"),
637 timetostring(getcurrenttime()));
638 for(i=0; i<us_pulldownmenucount; i++)
639 {
640 pm = us_pulldowns[i];
641 xprintf(io, x_("\n"));
642 us_dumppulldownmenu(io, pm, pm->header, x_(""));
643 }
644
645 xclose(io);
646 ttyputmsg(M_("Pulldown menus dumped to %s"), truename);
647 }
648
us_dumppulldownmenu(FILE * io,POPUPMENU * pm,CHAR * name,CHAR * prefix)649 void us_dumppulldownmenu(FILE *io, POPUPMENU *pm, CHAR *name, CHAR *prefix)
650 {
651 REGISTER POPUPMENUITEM *mi;
652 REGISTER USERCOM *uc;
653 REGISTER INTBIG i, j, k;
654 CHAR comname[300], subprefix[50];
655
656 for(k=j=0; name[k] != 0; k++)
657 if (name[k] != '&') comname[j++] = name[k];
658 comname[j] = 0;
659
660 xprintf(io, x_("%s%s:\n"), prefix, comname);
661 for(i=0; i<pm->total; i++)
662 {
663 mi = &pm->list[i];
664 uc = mi->response;
665 if (uc->active < 0)
666 {
667 xprintf(io, x_("%s ----------\n"), prefix);
668 continue;
669 }
670
671 for(k=j=0; mi->attribute[k] != 0; k++)
672 {
673 if (mi->attribute[k] == '&') continue;
674 if (mi->attribute[k] == '/') break;
675 comname[j++] = mi->attribute[k];
676 }
677 comname[j] = 0;
678
679 if (uc->menu != NOPOPUPMENU)
680 {
681 estrcpy(subprefix, prefix);
682 estrcat(subprefix, x_(" "));
683 us_dumppulldownmenu(io, uc->menu, comname, subprefix);
684 continue;
685 }
686 xprintf(io, x_("%s %s\n"), prefix, comname);
687 }
688 }
689