~ubuntu-branches/ubuntu/lucid/graphviz/lucid-security

« back to all changes in this revision

Viewing changes to lefty/dot2l/dot2l.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-02-05 18:52:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020205185212-8i04c70te00rc40y
Tags: upstream-1.7.16
ImportĀ upstreamĀ versionĀ 1.7.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#pragma prototyped
 
2
 
 
3
#include "common.h"
 
4
#include "mem.h"
 
5
#include "io.h"
 
6
#include "code.h"
 
7
#include "tbl.h"
 
8
#include "dot2l.h"
 
9
 
 
10
extern void lex_begin (int);
 
11
 
 
12
char *gtype, *etype;
 
13
int yaccdone;
 
14
int attrclass;
 
15
int inattrstmt;
 
16
 
 
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;
 
21
 
 
22
static jmp_buf ljbuf;
 
23
 
 
24
static void filllabeltable (Tobj, int);
 
25
static void filllabelrect (Tobj);
 
26
 
 
27
static char *lsp, *rsp;
 
28
 
 
29
static void writesgraph (int, Tobj, int, int, char *);
 
30
static void writeattr (int, Tobj, char *);
 
31
static void quotestring (char *, Tobj);
 
32
 
 
33
Tobj D2Lparsegraphlabel (Tobj lo, Tobj ro) {
 
34
    volatile long lm;
 
35
    volatile Tobj to;
 
36
 
 
37
    lm = Mpushmark (lo);
 
38
    Mpushmark (ro);
 
39
    to = Ttable (4);
 
40
    Mpushmark (to);
 
41
    lsp = Tgetstring (lo);
 
42
    if (ro && T_ISSTRING (ro))
 
43
        rsp = Tgetstring (ro);
 
44
    else
 
45
        rsp = NULL;
 
46
 
 
47
    if (setjmp (ljbuf)) {
 
48
        to = NULL;
 
49
        fprintf (stderr, "error in label >>%s<<\n", lsp);
 
50
    } else
 
51
        filllabeltable (to, TRUE);
 
52
    Mpopmark (lm);
 
53
    return to;
 
54
}
 
55
 
 
56
#define HASTEXT 1
 
57
#define HASPORT 2
 
58
#define HASTABLE 4
 
59
#define INTEXT 8
 
60
#define INPORT 16
 
61
 
 
62
#define ISCTRL(c) \
 
63
    ((c) == '{' || (c) == '}' || (c) == '|' || (c) == '<' || (c) == '>')
 
64
 
 
65
static void filllabeltable (Tobj to, int flag) {
 
66
    Tobj cto, fo;
 
67
    char *tsp, *psp, *hstsp, *hspsp;
 
68
    char text[10240], port[256];
 
69
    long cti;
 
70
    int mode, wflag, ishardspace;
 
71
 
 
72
    mode = 0;
 
73
    cti = 0;
 
74
    Tinsi (to, cti++, (cto = Ttable (2)));
 
75
    hstsp = tsp = &text[0], hspsp = psp = &port[0];
 
76
    wflag = TRUE;
 
77
    ishardspace = FALSE;
 
78
    while (wflag) {
 
79
        switch (*lsp) {
 
80
        case '<':
 
81
            if (mode & (HASTABLE | HASPORT))
 
82
                longjmp (ljbuf, 1); /* DOESN'T RETURN */
 
83
            mode &= ~INTEXT;
 
84
            mode |= (HASPORT | INPORT);
 
85
            lsp++;
 
86
            break;
 
87
        case '>':
 
88
            if (!(mode & INPORT))
 
89
                longjmp (ljbuf, 1); /* DOESN'T RETURN */
 
90
            mode &= ~INPORT;
 
91
            lsp++;
 
92
            break;
 
93
        case '{':
 
94
            lsp++;
 
95
            if (mode != 0 || !*lsp)
 
96
                longjmp (ljbuf, 1); /* DOESN'T RETURN */
 
97
            Tinss (cto, "fields", (fo = Ttable (2)));
 
98
            mode = HASTABLE;
 
99
            filllabeltable (fo, FALSE);
 
100
            break;
 
101
        case '}':
 
102
        case '|':
 
103
        case '\000':
 
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) == ' ')
 
108
                    psp--;
 
109
                *psp = '\000';
 
110
                Tinss (cto, "port", Tstring (&port[0]));
 
111
                hspsp = psp = &port[0];
 
112
            }
 
113
            if (!(mode & (HASTEXT | HASTABLE)))
 
114
                mode |= HASTEXT, *tsp++ = ' ';
 
115
            if (mode & HASTEXT) {
 
116
                if (tsp > &text[0] + 1 && tsp - 1 != hstsp && *(tsp - 1) == ' ')
 
117
                    tsp--;
 
118
                *tsp = '\000';
 
119
                Tinss (cto, "text", Tstring (&text[0]));
 
120
                hstsp = tsp = &text[0];
 
121
            }
 
122
            if (mode & (HASTEXT | HASPORT))
 
123
                filllabelrect (cto);
 
124
            if (*lsp) {
 
125
                if (*lsp == '}') {
 
126
                    lsp++;
 
127
                    return;
 
128
                }
 
129
                Tinsi (to, cti++, (cto = Ttable (2)));
 
130
                mode = 0;
 
131
                lsp++;
 
132
            } else
 
133
                wflag = FALSE;
 
134
            break;
 
135
        case '\\':
 
136
            if (*(lsp + 1))
 
137
                if (ISCTRL (*(lsp + 1)))
 
138
                    lsp++;
 
139
                else if (*(lsp + 1) == ' ')
 
140
                    ishardspace = TRUE, lsp++;
 
141
            /* falling through ... */
 
142
        default:
 
143
            if ((mode & HASTABLE) && *lsp != ' ')
 
144
                longjmp (ljbuf, 1); /* DOESN'T RETURN */
 
145
            if (!(mode & (INTEXT | INPORT)) && (ishardspace || *lsp != ' '))
 
146
                mode |= (INTEXT | HASTEXT);
 
147
            if (mode & INTEXT) {
 
148
                if (!(*lsp == ' ' && !ishardspace && *(tsp - 1) == ' '))
 
149
                    *tsp++ = *lsp;
 
150
                if (ishardspace)
 
151
                    hstsp = tsp - 1;
 
152
            } else if (mode & INPORT) {
 
153
                if (!(*lsp == ' ' && !ishardspace && (psp == &port[0] ||
 
154
                        *(psp - 1) == ' ')))
 
155
                    *psp++ = *lsp;
 
156
                if (ishardspace)
 
157
                    hspsp = psp - 1;
 
158
            }
 
159
            ishardspace = FALSE;
 
160
            lsp++;
 
161
            break;
 
162
        }
 
163
    }
 
164
    return;
 
165
}
 
166
 
 
167
static void filllabelrect (Tobj to) {
 
168
    Tobj ro, p0o, p1o;
 
169
    char *s2, *s3;
 
170
    char c, c2;
 
171
    int i;
 
172
 
 
173
    if (!rsp)
 
174
        return;
 
175
    for (s2 = rsp; *s2 && *s2 != ' '; s2++)
 
176
        ;
 
177
    c = *s2, *s2 = 0;
 
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++)
 
183
            ;
 
184
        c2 = *s3, *s3 = 0;
 
185
        if (s3 == rsp)
 
186
            longjmp (ljbuf, 1); /* DOESN'T RETURN */
 
187
        switch (i) {
 
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;
 
192
        }
 
193
        *s3 = c2;
 
194
        rsp = s3;
 
195
        if (*rsp == ',')
 
196
            rsp++;
 
197
    }
 
198
    *s2 = c;
 
199
    rsp = s2 + 1;
 
200
}
 
201
 
 
202
static Tobj nameo, attro, edgeso, hporto, tporto, heado, tailo, protogo;
 
203
 
 
204
Tobj D2Lreadgraph (int ioi, Tobj protograph) {
 
205
    graphframe_t *gframe, *tgframe;
 
206
    edgeframe_t *eframe, *teframe;
 
207
    Tobj graph;
 
208
    long m;
 
209
 
 
210
    protogo = protograph;
 
211
    nameo = Tstring ("name");
 
212
    m = Mpushmark (nameo);
 
213
    attro = Tstring ("attr");
 
214
    Mpushmark (attro);
 
215
    edgeso = Tstring ("edges");
 
216
    Mpushmark (edgeso);
 
217
    hporto = Tstring ("hport");
 
218
    Mpushmark (hporto);
 
219
    tporto = Tstring ("tport");
 
220
    Mpushmark (tporto);
 
221
    heado = Tstring ("head");
 
222
    Mpushmark (heado);
 
223
    tailo = Tstring ("tail");
 
224
    Mpushmark (tailo);
 
225
    yaccdone = FALSE;
 
226
    gstack = topgframe = NULL;
 
227
    errflag = FALSE;
 
228
    lex_begin (ioi);
 
229
    yyparse ();
 
230
    graph = NULL;
 
231
    if (topgframe) {
 
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)));
 
237
            }
 
238
            tgframe = gframe->next;
 
239
            Mfree (gframe, M_BYTE2SIZE (sizeof (graphframe_t)));
 
240
        }
 
241
        goto done;
 
242
    }
 
243
done:
 
244
    Mpopmark (m);
 
245
    return graph;
 
246
}
 
247
 
 
248
void D2Lwritegraph (int ioi, Tobj graph, int flag) {
 
249
    Tobj nodes, node, sgraphs, sgraph, edges, edge, tail, head, tport, hport;
 
250
    Tobj so, no, eo, to;
 
251
    char buf[10240];
 
252
    char *s;
 
253
    int isdag, n, nn, i;
 
254
 
 
255
    if (!(so = Tfinds (graph, "type")) || !T_ISSTRING (so))
 
256
        s = "digraph";
 
257
    else {
 
258
        s = Tgetstring (so);
 
259
        if (!*s)
 
260
            s = "digraph";
 
261
    }
 
262
    strcpy (buf, s);
 
263
    if (strcmp (s, "digraph") == 0 || strcmp (s, "strict digraph") == 0)
 
264
        isdag = 1;
 
265
    else
 
266
        isdag = 0;
 
267
    if (!(so = Tfinds (graph, "name")) || !T_ISSTRING (so))
 
268
        s = "g";
 
269
    else {
 
270
        s = Tgetstring (so);
 
271
        if (!*s)
 
272
            s = "g";
 
273
    }
 
274
    strcat (buf, " ");
 
275
    quotestring (buf, Tstring (s));
 
276
    strcat (buf, " {");
 
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]");
 
283
    }
 
284
    if ((to = Tfinds (graph, "nodeattr")) && T_ISTABLE (to)) {
 
285
        IOwriteline (ioi, "\tnode [");
 
286
        writeattr (ioi, to, buf);
 
287
        IOwriteline (ioi, "\t]");
 
288
    }
 
289
    if ((to = Tfinds (graph, "edgeattr")) && T_ISTABLE (to)) {
 
290
        IOwriteline (ioi, "\tedge [");
 
291
        writeattr (ioi, to, buf);
 
292
        IOwriteline (ioi, "\t]");
 
293
    }
 
294
    if ((nodes = Tfinds (graph, "nodes"))) {
 
295
        if (!(no = Tfinds (graph, "maxnid")) || !T_ISNUMBER (no))
 
296
            n = 100 * Tgettablen (nodes);
 
297
        else
 
298
            n = Tgetnumber (no);
 
299
        for (i = 0; i < n; i++) {
 
300
            if (!(node = Tfindi (nodes, i)))
 
301
                continue;
 
302
            buf[0] = '\t', buf[1] = 0;
 
303
            quotestring (buf, Tfinds (node, "name"));
 
304
            strcat (buf, " [");
 
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]");
 
310
        }
 
311
    }
 
312
    nn = n;
 
313
    if ((sgraphs = Tfinds (graph, "graphs"))) {
 
314
        if (!(no = Tfinds (graph, "maxgid")) || !T_ISNUMBER (no))
 
315
            n = 100 * Tgettablen (sgraphs);
 
316
        else
 
317
            n = Tgetnumber (no);
 
318
        for (i = 0; i < n; i++) {
 
319
            if (!(sgraph = Tfindi (sgraphs, i)) ||
 
320
                    Tfinds (sgraph, "wmark"))
 
321
                continue;
 
322
            buf[0] = '\t', buf[1] = 0;
 
323
            writesgraph (ioi, sgraph, n, nn, buf);
 
324
        }
 
325
        for (i = 0; i < n; i++) {
 
326
            if (!(sgraph = Tfindi (sgraphs, i)))
 
327
                continue;
 
328
            Tdels (sgraph, "wmark");
 
329
        }
 
330
    }
 
331
    if ((edges = Tfinds (graph, "edges"))) {
 
332
        if (!(eo = Tfinds (graph, "maxeid")) || !T_ISNUMBER (eo))
 
333
            n = 100 * Tgettablen (edges);
 
334
        else
 
335
            n = Tgetnumber (eo);
 
336
        for (i = 0; i < n; i++) {
 
337
            if (!(edge = Tfindi (edges, i)))
 
338
                continue;
 
339
            if (!(tail = Tfinds (edge, "tail")))
 
340
                continue;
 
341
            if (!(head = Tfinds (edge, "head")))
 
342
                continue;
 
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)) {
 
348
                strcat (buf, ":");
 
349
                quotestring (buf, tport);
 
350
            }
 
351
            strcat (buf, isdag ? " -> " : " -- ");
 
352
            quotestring (buf, Tfinds (head, "name"));
 
353
            if (hport && T_ISSTRING (hport)) {
 
354
                strcat (buf, ":");
 
355
                quotestring (buf, hport);
 
356
            }
 
357
            strcat (buf, " [");
 
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);
 
362
            if (flag) {
 
363
                sprintf (buf, "\t\tid = %d", i);
 
364
                IOwriteline (ioi, buf);
 
365
            }
 
366
            IOwriteline (ioi, "\t]");
 
367
        }
 
368
    }
 
369
    IOwriteline (ioi, "}");
 
370
}
 
371
 
 
372
static void writesgraph (int ioi, Tobj graph, int gn, int nn, char *buf) {
 
373
    Tobj nodes, node, sgraphs, sgraph, so, to;
 
374
    char *s1, *s2, *s3;
 
375
    int i;
 
376
 
 
377
    Tinss (graph, "wmark", Tinteger (1));
 
378
    s1 = buf + strlen (buf);
 
379
    if (!(so = Tfinds (graph, "name")) || !T_ISSTRING (so))
 
380
        sprintf (s1, "{");
 
381
    else {
 
382
        strcat (s1, "subgraph ");
 
383
        quotestring (s1, so);
 
384
        strcat (s1, " {");
 
385
    }
 
386
    IOwriteline (ioi, buf);
 
387
    s2 = s1 + 1;
 
388
    s3 = s2 + 1;
 
389
    *s1 = '\t', *s2 = 0;
 
390
    if ((to = Tfinds (graph, "graphattr")) && T_ISTABLE (to)) {
 
391
        strcat (s1, "graph [");
 
392
        IOwriteline (ioi, buf);
 
393
        *s2 = '\t', *s3 = 0;
 
394
        writeattr (ioi, to, buf);
 
395
        *s2 = 0;
 
396
        strcat (s1, "]");
 
397
        IOwriteline (ioi, buf);
 
398
        *s2 = 0;
 
399
    }
 
400
    if ((to = Tfinds (graph, "nodeattr")) && T_ISTABLE (to)) {
 
401
        strcat (s1, "node [");
 
402
        IOwriteline (ioi, buf);
 
403
        *s2 = '\t', *s3 = 0;
 
404
        writeattr (ioi, to, buf);
 
405
        *s2 = 0;
 
406
        strcat (s1, "]");
 
407
        IOwriteline (ioi, buf);
 
408
        *s2 = 0;
 
409
    }
 
410
    if ((to = Tfinds (graph, "edgeattr")) && T_ISTABLE (to)) {
 
411
        strcat (s1, "edge [");
 
412
        IOwriteline (ioi, buf);
 
413
        *s2 = '\t', *s3 = 0;
 
414
        writeattr (ioi, to, buf);
 
415
        *s2 = 0;
 
416
        strcat (s1, "]");
 
417
        IOwriteline (ioi, buf);
 
418
        *s2 = 0;
 
419
    }
 
420
    if ((nodes = Tfinds (graph, "nodes"))) {
 
421
        for (i = 0; i < nn; i++) {
 
422
            *s2 = 0;
 
423
            if (!(node = Tfindi (nodes, i)))
 
424
                continue;
 
425
            quotestring (buf, Tfinds (node, "name"));
 
426
            IOwriteline (ioi, buf);
 
427
        }
 
428
    }
 
429
    if ((sgraphs = Tfinds (graph, "graphs"))) {
 
430
        for (i = 0; i < gn; i++) {
 
431
            if (!(sgraph = Tfindi (sgraphs, i)) ||
 
432
                    Tfinds (sgraph, "wmark"))
 
433
                continue;
 
434
            *s2 = 0;
 
435
            writesgraph (ioi, sgraph, gn, nn, buf);
 
436
        }
 
437
    }
 
438
    *s1 = '}', *s2 = 0;
 
439
    IOwriteline (ioi, buf);
 
440
    *s1 = 0;
 
441
}
 
442
 
 
443
static void writeattr (int ioi, Tobj to, char *buf) {
 
444
    Tkvindex_t tkvi;
 
445
    char *s1, *s2, *s3;
 
446
 
 
447
    s1 = buf + strlen (buf);
 
448
    for (Tgetfirst (to, &tkvi); tkvi.kvp; Tgetnext (&tkvi)) {
 
449
        switch (Tgettype (tkvi.kvp->ko)) {
 
450
        case T_INTEGER:
 
451
            sprintf (s1, "%d = ", Tgetinteger (tkvi.kvp->ko));
 
452
            break;
 
453
        case T_REAL:
 
454
            sprintf (s1, "%lf = ", Tgetreal (tkvi.kvp->ko));
 
455
            break;
 
456
        case T_STRING:
 
457
            sprintf (s1, "%s = ", Tgetstring (tkvi.kvp->ko));
 
458
            break;
 
459
        }
 
460
        s2 = buf + strlen (buf);
 
461
        switch (Tgettype (tkvi.kvp->vo)) {
 
462
        case T_INTEGER:
 
463
            sprintf (s2, "\"%d\"", Tgetinteger (tkvi.kvp->vo));
 
464
            break;
 
465
        case T_REAL:
 
466
            sprintf (s2, "\"%lf\"", Tgetreal (tkvi.kvp->vo));
 
467
            break;
 
468
        case T_STRING:
 
469
            *s2++ = '"';
 
470
            for (s3 = Tgetstring (tkvi.kvp->vo); *s3; s3++)
 
471
                if (*s3 == '"')
 
472
                    *s2++ = '\\', *s2++ = *s3;
 
473
                else
 
474
                    *s2++ = *s3;
 
475
            *s2++ = '"', *s2 = 0;
 
476
            break;
 
477
        default:
 
478
            sprintf (s2, "\"\"");
 
479
            break;
 
480
        }
 
481
        IOwriteline (ioi, buf);
 
482
    }
 
483
    *s1 = 0;
 
484
}
 
485
 
 
486
static void quotestring (char *buf, Tobj so) {
 
487
    char *s1, *s2;
 
488
 
 
489
    s1 = buf + strlen (buf);
 
490
    *s1++ = '"';
 
491
    if (so && T_ISSTRING (so))
 
492
        for (s2 = Tgetstring (so); *s2; s2++)
 
493
            if (*s2 == '"')
 
494
                *s1++ = '\\', *s1++ = *s2;
 
495
            else
 
496
                *s1++ = *s2;
 
497
    *s1++ = '"', *s1 = 0;
 
498
}
 
499
 
 
500
void D2Lbegin (char *name) {
 
501
 
 
502
    newgid = neweid = newnid = 0;
 
503
    attrclass = GRAPH;
 
504
 
 
505
    if (!(gstack = Mallocate (sizeof (graphframe_t))))
 
506
        panic (POS, "D2Lbegingraph", "cannot allocate graph stack");
 
507
    gstack->next = NULL;
 
508
    gstack->estack = NULL;
 
509
    topgframe = gstack;
 
510
 
 
511
    gmark = Mpushmark ((gstack->g = Ttable (12)));
 
512
    Tinss (gstack->g, "type", Tstring (gtype));
 
513
    Tinss (gstack->g, "name", Tstring (name));
 
514
 
 
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)));
 
519
 
 
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)));
 
524
 
 
525
    /* attributes */
 
526
    gstack->gattr = gstack->nattr = gstack->eattr = NULL;
 
527
    if (protogo) {
 
528
        gstack->gattr = Tfinds (protogo, "graphattr");
 
529
        gstack->nattr = Tfinds (protogo, "nodeattr");
 
530
        gstack->eattr = Tfinds (protogo, "edgeattr");
 
531
    }
 
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;
 
539
}
 
540
 
 
541
void D2Lend (void) {
 
542
    Mpopmark (gmark);
 
543
    yaccdone = TRUE;
 
544
}
 
545
 
 
546
void D2Labort (void) {
 
547
    Mpopmark (gmark);
 
548
    errflag = TRUE;
 
549
    yaccdone = TRUE;
 
550
}
 
551
 
 
552
void D2Lpushgraph (char *name) {
 
553
    graphframe_t *gframe;
 
554
    Tobj g, idobj, nameobj;
 
555
    long gid;
 
556
 
 
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;
 
561
 
 
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");
 
570
        return;
 
571
    }
 
572
    if (!name)
 
573
        gid = newgid++, nameobj = Tinteger (gid),
 
574
                Tinso (gdict, nameobj, nameobj);
 
575
    else
 
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))
 
589
            break;
 
590
        Tinsi (gframe->graphs, gid, g);
 
591
    }
 
592
    return;
 
593
}
 
594
 
 
595
Tobj D2Lpopgraph (void) {
 
596
    graphframe_t *gframe;
 
597
    Tobj g;
 
598
 
 
599
    gframe = gstack, gstack = gstack->next;
 
600
    g = gframe->g;
 
601
    Mfree (gframe, M_BYTE2SIZE (sizeof (graphframe_t)));
 
602
    return g;
 
603
}
 
604
 
 
605
Tobj D2Linsertnode (char *name) {
 
606
    graphframe_t *gframe;
 
607
    Tobj n, idobj, nameobj;
 
608
    long nid, m;
 
609
 
 
610
    if ((idobj = Tfinds (ndict, name))) {
 
611
        nid = Tgetnumber (idobj), n = Tfindi (allnodes, nid);
 
612
    } else {
 
613
        m = Mpushmark ((nameobj = Tstring (name)));
 
614
        Tinso (ndict, nameobj, Tinteger ((nid = newnid++)));
 
615
        Mpopmark (m);
 
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));
 
620
    }
 
621
    for (gframe = gstack; gframe->nodes != allnodes; gframe = gframe->next) {
 
622
        if (Tfindi (gframe->nodes, nid))
 
623
            break;
 
624
        Tinsi (gframe->nodes, nid, n);
 
625
    }
 
626
    N = n;
 
627
    return n;
 
628
}
 
629
 
 
630
void D2Linsertedge (Tobj tail, char *tport, Tobj head, char *hport) {
 
631
    graphframe_t *gframe;
 
632
    Tobj e;
 
633
    long eid;
 
634
 
 
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);
 
648
}
 
649
 
 
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)));
 
658
}
 
659
 
 
660
void D2Lmidedge (int type, Tobj obj, char *port) {
 
661
    edgeframe_t *eframe;
 
662
 
 
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);
 
669
}
 
670
 
 
671
void D2Lendedge (void) {
 
672
    edgeframe_t *eframe, *hframe, *tframe;
 
673
    Tobj tnodes, hnodes;
 
674
    Tkvindex_t tkvi, hkvi;
 
675
 
 
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);
 
689
        } else {
 
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);
 
695
        }
 
696
        free (eframe->port);
 
697
        Mfree (eframe, M_BYTE2SIZE (sizeof (edgeframe_t)));
 
698
    }
 
699
    free (eframe->port);
 
700
    Mfree (eframe, M_BYTE2SIZE (sizeof (edgeframe_t)));
 
701
    Mpopmark (gstack->emark);
 
702
    gstack->estack = NULL;
 
703
}
 
704
 
 
705
void D2Lsetattr (char *name, char *value) {
 
706
    if (inattrstmt) {
 
707
        switch (attrclass) {
 
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;
 
711
        }
 
712
        return;
 
713
    }
 
714
    switch (attrclass) {
 
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;
 
719
    }
 
720
}