2
This software may only be used by you under license from AT&T Corp.
3
("AT&T"). A copy of AT&T's Source Code Agreement is available at
4
AT&T's Internet website having the URL:
5
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
6
If you received this software without first entering into a license
7
with AT&T, you have an infringing copy of this software and cannot use
8
it without violating AT&T's intellectual property rights.
12
/* Lefteris Koutsofios - AT&T Bell Laboratories */
25
TXT_SEEN, TXT_ABSTRACT, TXT_FULL
27
typedef struct txtnode_t {
35
struct txtnode_t *txtnode;
52
struct txtnode_t *list;
58
static txtnode_t *txtroot;
59
static txtnode_t defnode;
61
static txtnode_t **seenp;
62
static long seeni, seenn;
64
#define SEENSIZE sizeof (txtnode_t)
66
static Tobj txtvo2toggle = NULL;
68
static Gwattr_t arraydata[2], buttondata[5];
70
static int txton, txtx, txty, txtwidth, txtheight;
71
static int txtwi, queryws[G_QWMODES + 1], listwi, scrollwi, arraywi, cmdwi;
75
#define max(a, b) (((a) >= (b)) ? (a) : (b))
77
static void viewon (void);
78
static void viewoff (void);
79
static void update (txtnode_t *, long);
80
static void buildlist (txtnode_t *);
81
static void rebuildlist (txtnode_t *);
82
static void fillnode (txtnode_t *, txtnode_t *);
83
static void unfillnode (txtnode_t *);
84
static int cmp (const void *, const void *);
85
static txtnode_t *findseen (txtnode_t *);
86
static void add2seen (txtnode_t *);
87
static void orderfunc (void *, Gawdata_t *);
88
static void coordsfunc (int, Gawdata_t *);
89
static void coords2func (int, Gawdata_t *);
91
void TXTinit (Grect_t r) {
97
txtx = r.o.x, txty = r.o.y;
98
txtwidth = r.c.x - r.o.x + 1, txtheight = r.c.y - r.o.y + 1;
100
buttondata[0].id = G_ATTRBUTTONCB;
101
buttondata[0].u.func = TXTtoggle;
102
buttondata[1].id = G_ATTRSIZE;
103
buttondata[1].u.s.x = buttondata[1].u.s.y = 0;
104
buttondata[2].id = G_ATTRBORDERWIDTH;
105
buttondata[2].u.i = 0;
106
buttondata[3].id = G_ATTRTEXT;
107
buttondata[4].id = G_ATTRUSERDATA;
109
arraydata[0].id = G_ATTRRESIZECB;
110
arraydata[0].u.func = coordsfunc;
111
arraydata[1].id = G_ATTRSIZE;
112
arraydata[1].u.s.x = arraydata[1].u.s.y = 0;
114
defnode.mode = TXT_ABSTRACT;
115
defnode.ttype = T_TABLE;
116
defnode.ko = defnode.vo = NULL;
119
defnode.u.s.txtnode = NULL;
120
defnode.u.s.ko = NULL;
121
defnode.u.s.text = NULL;
123
defnode.u.a.text = NULL;
125
defnode.u.f.s.text = NULL;
126
defnode.u.f.s.wi = 0;
127
defnode.u.f.t.ftext = defnode.u.f.t.ltext = NULL;
128
defnode.u.f.t.fwi = 0;
129
defnode.u.f.t.mwi = 0;
130
defnode.u.f.t.lwi = 0;
131
defnode.u.f.t.list = NULL;
134
for (i = 1; i <= G_QWMODES; i++) {
135
data[0].id = G_ATTRMODE;
138
data[0].u.t = "string";
141
data[0].u.t = "file";
144
data[0].u.t = "choice";
147
queryws[i] = Gcreatewidget (-1, G_QUERYWIDGET, 1, &data[0]);
150
src.flag = CHARSRC, src.fp = NULL, src.tok = -1, src.lnum = 1;
153
void TXTterm (void) {
156
for (i = 1; i <= G_QWMODES; i++)
157
Gdestroywidget (queryws[i]);
159
viewoff (), txton = FALSE;
163
int TXTmode (int argc, lvar_t *argv) {
166
if (!argv[0].o || Tgettype (argv[0].o) != T_STRING)
168
s = Tgetstring (argv[0].o);
169
if (Strcmp (s, "on") == 0) {
172
} else if (Strcmp (s, "off") == 0) {
181
static void viewon (void) {
184
data[0].id = G_ATTRNAME;
185
data[0].u.t = "LEFTY text view";
186
data[1].id = G_ATTRORIGIN;
187
data[1].u.p.x = txtx, data[1].u.p.y = txty;
188
data[2].id = G_ATTRSIZE;
189
data[2].u.s.x = txtwidth, data[2].u.s.y = txtheight;
190
txtwi = Gcreatewidget (-1, G_VIEWWIDGET, 3, &data[0]);
192
data[0].id = G_ATTRSIZE;
193
data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight;
194
data[1].id = G_ATTRBORDERWIDTH;
196
data[2].id = G_ATTRRESIZECB;
197
data[2].u.func = coords2func;
198
listwi = Gcreatewidget (txtwi, G_ARRAYWIDGET, 3, &data[0]);
199
Gawsetmode (&Gwidgets[listwi], TRUE);
201
data[0].id = G_ATTRSIZE;
202
data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight / 3;
203
data[1].id = G_ATTRBORDERWIDTH;
205
data[2].id = G_ATTRTEXT;
207
data[3].id = G_ATTRNEWLINECB;
208
data[3].u.func = TXTprocess;
209
data[4].id = G_ATTRMODE;
210
data[4].u.t = "oneline";
211
cmdwi = Gcreatewidget (listwi, G_TEXTWIDGET, 5, &data[0]);
213
data[0].id = G_ATTRSIZE;
214
data[0].u.s.x = txtwidth, data[0].u.s.y = txtheight * 2 / 3;
215
data[1].id = G_ATTRMODE;
216
data[1].u.t = "forcebars";
217
scrollwi = Gcreatewidget (listwi, G_SCROLLWIDGET, 2, &data[0]);
219
data[0].id = G_ATTRRESIZECB;
220
data[0].u.func = coordsfunc;
221
data[1].id = G_ATTRSIZE;
222
data[1].u.s.x = txtwidth, data[1].u.s.y = txtheight;
223
data[2].id = G_ATTRBORDERWIDTH;
225
arraywi = Gcreatewidget (scrollwi, G_ARRAYWIDGET, 3, &data[0]);
227
Gawsetmode (&Gwidgets[listwi], FALSE);
229
if (!(txtroot = malloc (sizeof (txtnode_t))))
230
panic (POS, "TXTinit", "txtroot malloc failed");
232
txtroot->mode = TXT_FULL;
234
txtroot->path = NULL;
235
txtroot->u.f.t.mwi = arraywi;
237
seenp = Marrayalloc ((long) SEENINCR * SEENSIZE);
243
static void viewoff (void) {
246
unfillnode (txtroot);
248
Gdestroywidget (arraywi);
249
Gdestroywidget (scrollwi);
250
Gdestroywidget (cmdwi);
251
Gdestroywidget (listwi);
252
Gdestroywidget (txtwi);
258
int TXTask (int argc, lvar_t *argv) {
268
if (T_ISSTRING (so)) {
269
sp = Tgetstring (so);
270
if (Strcmp (sp, "string") == 0)
272
else if (Strcmp (sp, "file") == 0)
274
else if (Strcmp (sp, "choice") == 0)
283
ap = Tgetstring (ao);
285
if (Gqueryask (queryws[mode], Tgetstring (argv[0].o), ap, buf, 1200) == 0)
286
rtno = Tstring (buf);
290
if (mode == G_QWCHOICE) {
293
data[0].id = G_ATTRMODE;
294
data[0].u.t = "choice";
295
Gdestroywidget (queryws[mode]);
296
queryws[mode] = Gcreatewidget (-1, G_QUERYWIDGET, 1, &data[0]);
302
void TXTprocess (int wi, char *sp) {
306
if ((co = Punit (&src)))
307
Eoktorun = TRUE, Eunit (co);
310
void TXTupdate (void) {
316
update (txtroot, txtroot->time);
317
txtroot->time = Ttime;
321
void TXTtoggle (int wi, void *data) {
327
/* update is called only for TXT_FULL tables */
328
static void update (txtnode_t *pnode, long ptim) {
329
txtnode_t *cnode, *seennode;
333
Gawsetmode (&Gwidgets[pnode->u.f.t.mwi], TRUE);
334
if (!pnode->u.f.t.list)
336
else if (ptim < Tgettime (pnode->vo))
338
for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n;
341
if (txtvo2toggle == cnode->vo) {
342
switch (cnode->mode) {
347
cnode->mode = TXT_FULL;
348
fillnode (pnode, cnode);
352
cnode->mode = TXT_ABSTRACT;
353
fillnode (pnode, cnode);
357
if (!(seennode = findseen (cnode)))
359
if (seennode && cnode->mode == TXT_SEEN &&
360
seennode->ko != cnode->u.s.ko) {
362
cnode->u.s.txtnode = seennode;
363
cnode->u.s.ko = seennode->ko;
364
fillnode (pnode, cnode);
365
} else if (seennode && cnode->mode != TXT_SEEN) {
367
cnode->mode = TXT_SEEN;
368
cnode->u.s.txtnode = seennode;
369
cnode->u.s.ko = seennode->ko;
370
fillnode (pnode, cnode);
371
} else if (!seennode && cnode->mode == TXT_SEEN) {
373
cnode->mode = TXT_ABSTRACT;
374
fillnode (pnode, cnode);
375
} else if (cnode->time == -1) {
378
cnode->u.s.txtnode = seennode;
379
fillnode (pnode, cnode);
381
if (cnode->ttype == T_TABLE && cnode->mode == TXT_FULL)
382
update (cnode, ctim);
384
Gaworder (&Gwidgets[pnode->u.f.t.mwi], pnode, orderfunc);
385
Gawsetmode (&Gwidgets[pnode->u.f.t.mwi], FALSE);
388
static void buildlist (txtnode_t *pnode) {
394
pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
395
if (!(pnode->u.f.t.list =
396
malloc (max (pnode->u.f.t.n, 1) * sizeof (txtnode_t))))
397
panic (POS, "buildlist", "list malloc failed");
399
for (cnode = &pnode->u.f.t.list[0], Tgetfirst (pnode->vo, &tkvi);
400
tkvi.kvp; Tgetnext (&tkvi)) {
401
ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
402
vtype = Tgettype (vo);
403
if (vtype == T_CODE && TCgettype (vo, TCgetnext (vo, TCgetnext (vo,
404
TCgetnext (vo, TCgetfp (vo, 0))))) == C_INTERNAL) {
411
cnode->ttype = vtype;
414
qsort ((char *) pnode->u.f.t.list, pnode->u.f.t.n,
415
sizeof (txtnode_t), cmp);
418
static void rebuildlist (txtnode_t *pnode) {
423
txtnode_t *olist, *nlist;
425
int on, nn, i, j, cmpval;
427
olist = pnode->u.f.t.list;
429
pnode->u.f.t.n = ((Ttable_t *) pnode->vo)->n;
430
if (!(pnode->u.f.t.list =
431
malloc (max (pnode->u.f.t.n, 1) * sizeof (txtnode_t))))
432
panic (POS, "rebuildlist", "list malloc failed");
434
for (cnode = &pnode->u.f.t.list[0], Tgetfirst (pnode->vo, &tkvi);
435
tkvi.kvp; Tgetnext (&tkvi)) {
436
ko = tkvi.kvp->ko, vo = tkvi.kvp->vo;
437
vtype = Tgettype (vo);
438
if (vtype == T_CODE && TCgettype (vo, TCgetnext (vo, TCgetnext (vo,
439
TCgetnext (vo, TCgetfp (vo, 0))))) == C_INTERNAL) {
446
cnode->ttype = vtype;
449
qsort ((char *) pnode->u.f.t.list, pnode->u.f.t.n, sizeof (txtnode_t), cmp);
450
nlist = pnode->u.f.t.list;
452
for (i = 0, j = 0; i < nn; i++) {
453
while (j < on && (cmpval = cmp (&olist[j], &nlist[i])) < 0)
455
if (j < on && cmpval == 0 && nlist[i].vo == olist[j].vo)
456
tmpnode = olist[j], olist[j] = nlist[i], nlist[i] = tmpnode, j++;
458
for (j = 0; j < on; j++)
459
unfillnode (&olist[j]);
463
static void fillnode (txtnode_t *pnode, txtnode_t *cnode) {
465
cnode->path = Spath (pnode->path, cnode->ko);
466
switch (cnode->mode) {
468
cnode->u.s.text = Sseen (cnode->ko, cnode->u.s.txtnode->path);
469
buttondata[3].u.t = cnode->u.s.text;
470
buttondata[4].u.u = (unsigned long) cnode->vo;
471
cnode->u.s.wi = Gcreatewidget (pnode->u.f.t.mwi,
472
G_BUTTONWIDGET, 5, &buttondata[0]);
475
cnode->u.a.text = Sabstract (cnode->ko, cnode->vo);
476
buttondata[3].u.t = cnode->u.a.text;
477
buttondata[4].u.u = (unsigned long) cnode->vo;
478
cnode->u.a.wi = Gcreatewidget (pnode->u.f.t.mwi,
479
G_BUTTONWIDGET, 5, &buttondata[0]);
482
if (cnode->ttype == T_TABLE) {
483
cnode->u.f.t.ftext = Stfull (cnode->ko);
484
cnode->u.f.t.ltext = "];";
485
buttondata[3].u.t = cnode->u.f.t.ftext;
486
buttondata[4].u.u = (unsigned long) cnode->vo;
487
cnode->u.f.t.fwi = Gcreatewidget (pnode->u.f.t.mwi,
488
G_BUTTONWIDGET, 5, &buttondata[0]);
489
cnode->u.f.t.mwi = Gcreatewidget (pnode->u.f.t.mwi,
490
G_ARRAYWIDGET, 2, &arraydata[0]);
491
buttondata[3].u.t = cnode->u.f.t.ltext;
492
buttondata[4].u.u = (unsigned long) cnode->vo;
493
cnode->u.f.t.lwi = Gcreatewidget (pnode->u.f.t.mwi,
494
G_BUTTONWIDGET, 5, &buttondata[0]);
496
cnode->u.f.s.text = Ssfull (cnode->ko, cnode->vo);
497
buttondata[3].u.t = cnode->u.f.s.text;
498
buttondata[4].u.u = (unsigned long) cnode->vo;
499
cnode->u.f.s.wi = Gcreatewidget (pnode->u.f.t.mwi,
500
G_BUTTONWIDGET, 5, &buttondata[0]);
506
static void unfillnode (txtnode_t *cnode) {
510
free (cnode->path), cnode->path = NULL;
511
switch (cnode->mode) {
514
free (cnode->u.s.text);
516
Gdestroywidget (cnode->u.s.wi);
520
free (cnode->u.a.text);
522
Gdestroywidget (cnode->u.a.wi);
525
if (cnode->ttype == T_TABLE) {
526
for (i = 0; i < cnode->u.f.t.n; i++)
527
unfillnode (&cnode->u.f.t.list[i]);
528
if (cnode->u.f.t.list)
529
free (cnode->u.f.t.list);
530
if (cnode->u.f.t.ftext)
531
free (cnode->u.f.t.ftext);
532
if (cnode->u.f.t.fwi) {
533
Gdestroywidget (cnode->u.f.t.fwi);
534
Gdestroywidget (cnode->u.f.t.mwi);
535
Gdestroywidget (cnode->u.f.t.lwi);
538
if (cnode->u.f.s.text)
539
free (cnode->u.f.s.text);
541
Gdestroywidget (cnode->u.f.s.wi);
545
cnode->u.s.text = NULL;
547
cnode->u.a.text = NULL;
549
cnode->u.f.t.list = NULL;
550
cnode->u.f.t.ftext = NULL;
551
cnode->u.f.t.fwi = 0;
552
cnode->u.f.t.mwi = 0;
553
cnode->u.f.t.lwi = 0;
554
cnode->u.f.s.text = NULL;
558
static int cmp (const void *a, const void *b) {
559
Ttype_t atype, btype;
560
txtnode_t *anode, *bnode;
563
anode = (txtnode_t *) a, bnode = (txtnode_t *) b;
564
atype = Tgettype (anode->ko), btype = Tgettype (bnode->ko);
566
return (atype - btype);
567
if (atype == T_STRING)
568
return Strcmp (Tgetstring (anode->ko), Tgetstring (bnode->ko));
569
if (atype == T_INTEGER)
570
d1 = Tgetinteger (anode->ko), d2 = Tgetinteger (bnode->ko);
571
else if (atype == T_REAL)
572
d1 = Tgetreal (anode->ko), d2 = Tgetreal (bnode->ko);
578
return 0; /* but this should never happen since keys are unique */
581
static txtnode_t *findseen (txtnode_t *cnode) {
584
for (i = 0; i < seeni; i++)
585
if (seenp[i]->vo == cnode->vo)
590
static void add2seen (txtnode_t *cnode) {
591
if (seeni >= seenn) {
592
seenp = Marraygrow (seenp, (long) (seenn + SEENINCR) * SEENSIZE);
595
seenp[seeni++] = cnode;
598
static void orderfunc (void *data, Gawdata_t *dp) {
599
txtnode_t *pnode, *cnode;
604
for (i = 0, cnode = &pnode->u.f.t.list[0]; i < pnode->u.f.t.n; i++, cnode++)
605
switch (cnode->mode) {
607
dp->carray[dp->cj++].w = Gwidgets[cnode->u.s.wi].w;
610
dp->carray[dp->cj++].w = Gwidgets[cnode->u.a.wi].w;
613
if (cnode->ttype == T_TABLE) {
614
dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.fwi].w;
615
dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.mwi].w;
616
dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.t.lwi].w;
618
dp->carray[dp->cj++].w = Gwidgets[cnode->u.f.s.wi].w;
623
static void coordsfunc (int wi, Gawdata_t *dp) {
629
for (ci = 0; ci < dp->cj; ci++) {
630
cp = &dp->carray[ci];
633
cp->ox = cox, cp->oy = coy;
634
cp->sx = dp->sx - 2 * cp->bs;
635
coy += cp->sy + 2 * cp->bs;
640
static void coords2func (int wi, Gawdata_t *dp) {
646
for (ci = 0, cj = 0; ci < dp->cj; ci++) {
647
cp = &dp->carray[ci];
650
cp->ox = cox, cp->oy = coy;
652
cp->sx = dp->sx - 2 * cp->bs;
654
cp->sy = dp->sy - coy - 2 * cp->bs;
655
coy += cp->sy + 2 * cp->bs;