10
extern void lex_begin (int);
17
static graphframe_t *gstack, *topgframe;
18
static Tobj allgraphs, alledges, allnodes;
19
static Tobj gdict, edict, ndict, N;
20
static long newgid, neweid, newnid, gmark, errflag;
24
static void filllabeltable (Tobj, int);
25
static void filllabelrect (Tobj);
27
static char *lsp, *rsp;
29
static void writesgraph (int, Tobj, int, int, char *);
30
static void writeattr (int, Tobj, char *);
31
static void quotestring (char *, Tobj);
33
Tobj D2Lparsegraphlabel (Tobj lo, Tobj ro) {
41
lsp = Tgetstring (lo);
42
if (ro && T_ISSTRING (ro))
43
rsp = Tgetstring (ro);
49
fprintf (stderr, "error in label >>%s<<\n", lsp);
51
filllabeltable (to, TRUE);
63
((c) == '{' || (c) == '}' || (c) == '|' || (c) == '<' || (c) == '>')
65
static void filllabeltable (Tobj to, int flag) {
67
char *tsp, *psp, *hstsp, *hspsp;
68
char text[10240], port[256];
70
int mode, wflag, ishardspace;
74
Tinsi (to, cti++, (cto = Ttable (2)));
75
hstsp = tsp = &text[0], hspsp = psp = &port[0];
81
if (mode & (HASTABLE | HASPORT))
82
longjmp (ljbuf, 1); /* DOESN'T RETURN */
84
mode |= (HASPORT | INPORT);
89
longjmp (ljbuf, 1); /* DOESN'T RETURN */
95
if (mode != 0 || !*lsp)
96
longjmp (ljbuf, 1); /* DOESN'T RETURN */
97
Tinss (cto, "fields", (fo = Ttable (2)));
99
filllabeltable (fo, FALSE);
104
if ((!*lsp && !flag) || (mode & INPORT))
105
longjmp (ljbuf, 1); /* DOESN'T RETURN */
106
if (mode & HASPORT) {
107
if (psp > &port[0] + 1 && psp - 1 != hspsp && *(psp - 1) == ' ')
110
Tinss (cto, "port", Tstring (&port[0]));
111
hspsp = psp = &port[0];
113
if (!(mode & (HASTEXT | HASTABLE)))
114
mode |= HASTEXT, *tsp++ = ' ';
115
if (mode & HASTEXT) {
116
if (tsp > &text[0] + 1 && tsp - 1 != hstsp && *(tsp - 1) == ' ')
119
Tinss (cto, "text", Tstring (&text[0]));
120
hstsp = tsp = &text[0];
122
if (mode & (HASTEXT | HASPORT))
129
Tinsi (to, cti++, (cto = Ttable (2)));
137
if (ISCTRL (*(lsp + 1)))
139
else if (*(lsp + 1) == ' ')
140
ishardspace = TRUE, lsp++;
141
/* falling through ... */
143
if ((mode & HASTABLE) && *lsp != ' ')
144
longjmp (ljbuf, 1); /* DOESN'T RETURN */
145
if (!(mode & (INTEXT | INPORT)) && (ishardspace || *lsp != ' '))
146
mode |= (INTEXT | HASTEXT);
148
if (!(*lsp == ' ' && !ishardspace && *(tsp - 1) == ' '))
152
} else if (mode & INPORT) {
153
if (!(*lsp == ' ' && !ishardspace && (psp == &port[0] ||
167
static void filllabelrect (Tobj to) {
175
for (s2 = rsp; *s2 && *s2 != ' '; s2++)
178
Tinss (to, "rect", (ro = Ttable (2)));
179
Tinsi (ro, 0, (p0o = Ttable (2)));
180
Tinsi (ro, 1, (p1o = Ttable (2)));
181
for (i = 0; i < 4; i++) {
182
for (s3 = rsp; *s3 && *s3 != ','; s3++)
186
longjmp (ljbuf, 1); /* DOESN'T RETURN */
188
case 0: Tinss (p0o, "x", Tinteger ((long) atoi (rsp))); break;
189
case 1: Tinss (p0o, "y", Tinteger ((long) atoi (rsp))); break;
190
case 2: Tinss (p1o, "x", Tinteger ((long) atoi (rsp))); break;
191
case 3: Tinss (p1o, "y", Tinteger ((long) atoi (rsp))); break;
202
static Tobj nameo, attro, edgeso, hporto, tporto, heado, tailo, protogo;
204
Tobj D2Lreadgraph (int ioi, Tobj protograph) {
205
graphframe_t *gframe, *tgframe;
206
edgeframe_t *eframe, *teframe;
210
protogo = protograph;
211
nameo = Tstring ("name");
212
m = Mpushmark (nameo);
213
attro = Tstring ("attr");
215
edgeso = Tstring ("edges");
217
hporto = Tstring ("hport");
219
tporto = Tstring ("tport");
221
heado = Tstring ("head");
223
tailo = Tstring ("tail");
226
gstack = topgframe = NULL;
232
graph = (errflag) ? NULL : topgframe->g;
233
for (gframe = gstack; gframe; gframe = tgframe) {
234
for (eframe = gframe->estack; eframe; eframe = teframe) {
235
teframe = eframe->next;
236
Mfree (eframe, M_BYTE2SIZE (sizeof (edgeframe_t)));
238
tgframe = gframe->next;
239
Mfree (gframe, M_BYTE2SIZE (sizeof (graphframe_t)));
248
void D2Lwritegraph (int ioi, Tobj graph, int flag) {
249
Tobj nodes, node, sgraphs, sgraph, edges, edge, tail, head, tport, hport;
255
if (!(so = Tfinds (graph, "type")) || !T_ISSTRING (so))
263
if (strcmp (s, "digraph") == 0 || strcmp (s, "strict digraph") == 0)
267
if (!(so = Tfinds (graph, "name")) || !T_ISSTRING (so))
275
quotestring (buf, Tstring (s));
277
IOwriteline (ioi, buf);
278
buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
279
if ((to = Tfinds (graph, "graphattr")) && T_ISTABLE (to)) {
280
IOwriteline (ioi, "\tgraph [");
281
writeattr (ioi, to, buf);
282
IOwriteline (ioi, "\t]");
284
if ((to = Tfinds (graph, "nodeattr")) && T_ISTABLE (to)) {
285
IOwriteline (ioi, "\tnode [");
286
writeattr (ioi, to, buf);
287
IOwriteline (ioi, "\t]");
289
if ((to = Tfinds (graph, "edgeattr")) && T_ISTABLE (to)) {
290
IOwriteline (ioi, "\tedge [");
291
writeattr (ioi, to, buf);
292
IOwriteline (ioi, "\t]");
294
if ((nodes = Tfinds (graph, "nodes"))) {
295
if (!(no = Tfinds (graph, "maxnid")) || !T_ISNUMBER (no))
296
n = 100 * Tgettablen (nodes);
299
for (i = 0; i < n; i++) {
300
if (!(node = Tfindi (nodes, i)))
302
buf[0] = '\t', buf[1] = 0;
303
quotestring (buf, Tfinds (node, "name"));
305
IOwriteline (ioi, buf);
306
buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
307
if ((to = Tfinds (node, "attr")))
308
writeattr (ioi, to, buf);
309
IOwriteline (ioi, "\t]");
313
if ((sgraphs = Tfinds (graph, "graphs"))) {
314
if (!(no = Tfinds (graph, "maxgid")) || !T_ISNUMBER (no))
315
n = 100 * Tgettablen (sgraphs);
318
for (i = 0; i < n; i++) {
319
if (!(sgraph = Tfindi (sgraphs, i)) ||
320
Tfinds (sgraph, "wmark"))
322
buf[0] = '\t', buf[1] = 0;
323
writesgraph (ioi, sgraph, n, nn, buf);
325
for (i = 0; i < n; i++) {
326
if (!(sgraph = Tfindi (sgraphs, i)))
328
Tdels (sgraph, "wmark");
331
if ((edges = Tfinds (graph, "edges"))) {
332
if (!(eo = Tfinds (graph, "maxeid")) || !T_ISNUMBER (eo))
333
n = 100 * Tgettablen (edges);
336
for (i = 0; i < n; i++) {
337
if (!(edge = Tfindi (edges, i)))
339
if (!(tail = Tfinds (edge, "tail")))
341
if (!(head = Tfinds (edge, "head")))
343
tport = Tfinds (edge, "tport");
344
hport = Tfinds (edge, "hport");
345
buf[0] = '\t', buf[1] = 0;
346
quotestring (buf, Tfinds (tail, "name"));
347
if (tport && T_ISSTRING (tport)) {
349
quotestring (buf, tport);
351
strcat (buf, isdag ? " -> " : " -- ");
352
quotestring (buf, Tfinds (head, "name"));
353
if (hport && T_ISSTRING (hport)) {
355
quotestring (buf, hport);
358
IOwriteline (ioi, buf);
359
buf[0] = '\t', buf[1] = '\t', buf[2] = 0;
360
if ((to = Tfinds (edge, "attr")))
361
writeattr (ioi, to, buf);
363
sprintf (buf, "\t\tid = %d", i);
364
IOwriteline (ioi, buf);
366
IOwriteline (ioi, "\t]");
369
IOwriteline (ioi, "}");
372
static void writesgraph (int ioi, Tobj graph, int gn, int nn, char *buf) {
373
Tobj nodes, node, sgraphs, sgraph, so, to;
377
Tinss (graph, "wmark", Tinteger (1));
378
s1 = buf + strlen (buf);
379
if (!(so = Tfinds (graph, "name")) || !T_ISSTRING (so))
382
strcat (s1, "subgraph ");
383
quotestring (s1, so);
386
IOwriteline (ioi, buf);
390
if ((to = Tfinds (graph, "graphattr")) && T_ISTABLE (to)) {
391
strcat (s1, "graph [");
392
IOwriteline (ioi, buf);
394
writeattr (ioi, to, buf);
397
IOwriteline (ioi, buf);
400
if ((to = Tfinds (graph, "nodeattr")) && T_ISTABLE (to)) {
401
strcat (s1, "node [");
402
IOwriteline (ioi, buf);
404
writeattr (ioi, to, buf);
407
IOwriteline (ioi, buf);
410
if ((to = Tfinds (graph, "edgeattr")) && T_ISTABLE (to)) {
411
strcat (s1, "edge [");
412
IOwriteline (ioi, buf);
414
writeattr (ioi, to, buf);
417
IOwriteline (ioi, buf);
420
if ((nodes = Tfinds (graph, "nodes"))) {
421
for (i = 0; i < nn; i++) {
423
if (!(node = Tfindi (nodes, i)))
425
quotestring (buf, Tfinds (node, "name"));
426
IOwriteline (ioi, buf);
429
if ((sgraphs = Tfinds (graph, "graphs"))) {
430
for (i = 0; i < gn; i++) {
431
if (!(sgraph = Tfindi (sgraphs, i)) ||
432
Tfinds (sgraph, "wmark"))
435
writesgraph (ioi, sgraph, gn, nn, buf);
439
IOwriteline (ioi, buf);
443
static void writeattr (int ioi, Tobj to, char *buf) {
447
s1 = buf + strlen (buf);
448
for (Tgetfirst (to, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
449
switch (Tgettype (tkvi.kvp->ko)) {
451
sprintf (s1, "%d = ", Tgetinteger (tkvi.kvp->ko));
454
sprintf (s1, "%lf = ", Tgetreal (tkvi.kvp->ko));
457
sprintf (s1, "%s = ", Tgetstring (tkvi.kvp->ko));
460
s2 = buf + strlen (buf);
461
switch (Tgettype (tkvi.kvp->vo)) {
463
sprintf (s2, "\"%d\"", Tgetinteger (tkvi.kvp->vo));
466
sprintf (s2, "\"%lf\"", Tgetreal (tkvi.kvp->vo));
470
for (s3 = Tgetstring (tkvi.kvp->vo); *s3; s3++)
472
*s2++ = '\\', *s2++ = *s3;
475
*s2++ = '"', *s2 = 0;
478
sprintf (s2, "\"\"");
481
IOwriteline (ioi, buf);
486
static void quotestring (char *buf, Tobj so) {
489
s1 = buf + strlen (buf);
491
if (so && T_ISSTRING (so))
492
for (s2 = Tgetstring (so); *s2; s2++)
494
*s1++ = '\\', *s1++ = *s2;
497
*s1++ = '"', *s1 = 0;
500
void D2Lbegin (char *name) {
502
newgid = neweid = newnid = 0;
505
if (!(gstack = Mallocate (sizeof (graphframe_t))))
506
panic (POS, "D2Lbegingraph", "cannot allocate graph stack");
508
gstack->estack = NULL;
511
gmark = Mpushmark ((gstack->g = Ttable (12)));
512
Tinss (gstack->g, "type", Tstring (gtype));
513
Tinss (gstack->g, "name", Tstring (name));
515
/* the dictionaries */
516
Tinss (gstack->g, "graphdict", (gdict = Ttable (10)));
517
Tinss (gstack->g, "nodedict", (ndict = Ttable (10)));
518
Tinss (gstack->g, "edgedict", (edict = Ttable (10)));
520
/* this graph's nodes, edges, subgraphs */
521
Tinss (gstack->g, "nodes", (allnodes = gstack->nodes = Ttable (10)));
522
Tinss (gstack->g, "graphs", (allgraphs = gstack->graphs = Ttable (10)));
523
Tinss (gstack->g, "edges", (alledges = gstack->edges = Ttable (10)));
526
gstack->gattr = gstack->nattr = gstack->eattr = NULL;
528
gstack->gattr = Tfinds (protogo, "graphattr");
529
gstack->nattr = Tfinds (protogo, "nodeattr");
530
gstack->eattr = Tfinds (protogo, "edgeattr");
532
gstack->gattr = (gstack->gattr ? Tcopy (gstack->gattr) : Ttable (10));
533
Tinss (gstack->g, "graphattr", gstack->gattr);
534
gstack->nattr = (gstack->nattr ? Tcopy (gstack->nattr) : Ttable (10));
535
Tinss (gstack->g, "nodeattr", gstack->nattr);
536
gstack->eattr = (gstack->eattr ? Tcopy (gstack->eattr) : Ttable (10));
537
Tinss (gstack->g, "edgeattr", gstack->eattr);
538
gstack->ecopy = gstack->eattr;
546
void D2Labort (void) {
552
void D2Lpushgraph (char *name) {
553
graphframe_t *gframe;
554
Tobj g, idobj, nameobj;
557
if (!(gframe = Mallocate (sizeof (graphframe_t))))
558
panic (POS, "D2Lpushgraph", "cannot allocate graph stack");
559
gframe->next = gstack, gstack = gframe;
560
gstack->estack = NULL;
562
if (name && (idobj = Tfinds (gdict, name))) {
563
gid = Tgetnumber (idobj), gstack->g = g = Tfindi (allgraphs, gid);
564
gstack->nodes = Tfinds (g, "nodes");
565
gstack->graphs = Tfinds (g, "graphs");
566
gstack->edges = Tfinds (g, "edges");
567
gstack->gattr = Tfinds (g, "graphattr");
568
gstack->nattr = Tfinds (g, "nodeattr");
569
gstack->ecopy = gstack->eattr = Tfinds (g, "edgeattr");
573
gid = newgid++, nameobj = Tinteger (gid),
574
Tinso (gdict, nameobj, nameobj);
576
Tinso (gdict, (nameobj = Tstring (name)), Tinteger ((gid = newgid++)));
577
Tinsi (allgraphs, gid, (gstack->g = g = Ttable (10)));
578
Tinss (g, "name", nameobj);
579
Tinss (g, "nodes", (gstack->nodes = Ttable (10)));
580
Tinss (g, "graphs", (gstack->graphs = Ttable (10)));
581
Tinss (g, "edges", (gstack->edges = Ttable (10)));
582
Tinss (g, "graphattr", (gstack->gattr = Tcopy (gstack->next->gattr)));
583
Tinss (g, "nodeattr", (gstack->nattr = Tcopy (gstack->next->nattr)));
584
Tinss (g, "edgeattr",
585
(gstack->ecopy = gstack->eattr = Tcopy (gstack->next->eattr)));
586
for (gframe = gstack->next; gframe->graphs != allgraphs;
587
gframe = gframe->next) {
588
if (Tfindi (gframe->graphs, gid))
590
Tinsi (gframe->graphs, gid, g);
595
Tobj D2Lpopgraph (void) {
596
graphframe_t *gframe;
599
gframe = gstack, gstack = gstack->next;
601
Mfree (gframe, M_BYTE2SIZE (sizeof (graphframe_t)));
605
Tobj D2Linsertnode (char *name) {
606
graphframe_t *gframe;
607
Tobj n, idobj, nameobj;
610
if ((idobj = Tfinds (ndict, name))) {
611
nid = Tgetnumber (idobj), n = Tfindi (allnodes, nid);
613
m = Mpushmark ((nameobj = Tstring (name)));
614
Tinso (ndict, nameobj, Tinteger ((nid = newnid++)));
616
Tinsi (allnodes, nid, (n = Ttable (3)));
617
Tinso (n, nameo, nameobj);
618
Tinso (n, attro, Tcopy (gstack->nattr));
619
Tinso (n, edgeso, Ttable (2));
621
for (gframe = gstack; gframe->nodes != allnodes; gframe = gframe->next) {
622
if (Tfindi (gframe->nodes, nid))
624
Tinsi (gframe->nodes, nid, n);
630
void D2Linsertedge (Tobj tail, char *tport, Tobj head, char *hport) {
631
graphframe_t *gframe;
635
Tinsi (alledges, (eid = neweid++),
636
(e = Ttable ((long) (3 + (tport ? 1 : 0) + (hport ? 1 : 0)))));
637
Tinso (e, tailo, tail);
638
if (tport && tport[0])
639
Tinso (e, tporto, Tstring (tport));
640
Tinso (e, heado, head);
641
if (hport && hport[0])
642
Tinso (e, hporto, Tstring (hport));
643
Tinso (e, attro, Tcopy (gstack->ecopy));
644
Tinsi (Tfinds (head, "edges"), eid, e);
645
Tinsi (Tfinds (tail, "edges"), eid, e);
646
for (gframe = gstack; gframe->edges != alledges; gframe = gframe->next)
647
Tinsi (gframe->edges, eid, e);
650
void D2Lbeginedge (int type, Tobj obj, char *port) {
651
if (!(gstack->estack = Mallocate (sizeof (edgeframe_t))))
652
panic (POS, "D2Lbeginedge", "cannot allocate edge stack");
653
gstack->estack->next = NULL;
654
gstack->estack->type = type;
655
gstack->estack->obj = obj;
656
gstack->estack->port = strdup (port);
657
gstack->emark = Mpushmark ((gstack->ecopy = Tcopy (gstack->eattr)));
660
void D2Lmidedge (int type, Tobj obj, char *port) {
663
if (!(eframe = Mallocate (sizeof (edgeframe_t))))
664
panic (POS, "D2Lmidedge", "cannot allocate edge stack");
665
eframe->next = gstack->estack, gstack->estack = eframe;
666
gstack->estack->type = type;
667
gstack->estack->obj = obj;
668
gstack->estack->port = strdup (port);
671
void D2Lendedge (void) {
672
edgeframe_t *eframe, *hframe, *tframe;
674
Tkvindex_t tkvi, hkvi;
676
for (eframe = gstack->estack; eframe->next; eframe = tframe) {
677
hframe = eframe, tframe = eframe->next;
678
if (hframe->type == NODE && tframe->type == NODE) {
679
D2Linsertedge (tframe->obj, tframe->port,
680
hframe->obj, hframe->port);
681
} else if (hframe->type == NODE && tframe->type == GRAPH) {
682
tnodes = Tfinds (tframe->obj, "nodes");
683
for (Tgetfirst (tnodes, &tkvi); tkvi.kvp; Tgetnext (&tkvi))
684
D2Linsertedge (tkvi.kvp->vo, NULL, hframe->obj, hframe->port);
685
} else if (eframe->type == GRAPH && eframe->next->type == NODE) {
686
hnodes = Tfinds (hframe->obj, "nodes");
687
for (Tgetfirst (hnodes, &hkvi); hkvi.kvp; Tgetnext (&hkvi))
688
D2Linsertedge (tframe->obj, tframe->port, hkvi.kvp->vo, NULL);
690
tnodes = Tfinds (tframe->obj, "nodes");
691
hnodes = Tfinds (hframe->obj, "nodes");
692
for (Tgetfirst (tnodes, &tkvi); tkvi.kvp; Tgetnext (&tkvi))
693
for (Tgetfirst (hnodes, &hkvi); hkvi.kvp; Tgetnext (&hkvi))
694
D2Linsertedge (tkvi.kvp->vo, NULL, hkvi.kvp->vo, NULL);
697
Mfree (eframe, M_BYTE2SIZE (sizeof (edgeframe_t)));
700
Mfree (eframe, M_BYTE2SIZE (sizeof (edgeframe_t)));
701
Mpopmark (gstack->emark);
702
gstack->estack = NULL;
705
void D2Lsetattr (char *name, char *value) {
708
case NODE: Tinss (gstack->nattr, name, Tstring (value)); break;
709
case EDGE: Tinss (gstack->eattr, name, Tstring (value)); break;
710
case GRAPH: Tinss (gstack->gattr, name, Tstring (value)); break;
715
case NODE: Tinss (Tfinds (N, "attr"), name, Tstring (value)); break;
716
case EDGE: Tinss (gstack->ecopy, name, Tstring (value)); break;
717
/* a subgraph cannot have optional attrs? */
718
case GRAPH: Tinss (gstack->gattr, name, Tstring (value)); break;