~ubuntu-branches/ubuntu/precise/graphviz/precise-security

« back to all changes in this revision

Viewing changes to cmd/tools/gvpack.c

  • Committer: Bazaar Package Importer
  • Author(s): David Claughton
  • Date: 2010-03-24 22:45:18 UTC
  • mfrom: (1.2.7 upstream) (6.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100324224518-do441tthbqjaqjzd
Tags: 2.26.3-4
Add patch to fix segfault in circo. Backported from upstream snapshot
release.  Thanks to Francis Russell for his work on this.
(Closes: #575255)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: gvpack.c,v 1.14 2007/08/08 23:00:58 erg Exp $ $Revision: 1.14 $ */
 
1
/* $Id: gvpack.c,v 1.35 2010/01/08 21:28:39 erg Exp $ $Revision: 1.35 $ */
2
2
/* vim:set shiftwidth=4 ts=8: */
3
3
 
4
4
/**********************************************************
30
30
#endif
31
31
 
32
32
#include <assert.h>
33
 
#include <gvc.h>
34
 
#include <render.h>
35
 
#include <neatoprocs.h>
36
 
#include <ingraphs.h>
37
 
#include <pack.h>
38
 
#include <assert.h>
39
 
 
40
 
#include "builddate.h"
41
 
 
 
33
#include "gvc.h"
 
34
#include "render.h"
 
35
#include "neatoprocs.h"
 
36
#include "ingraphs.h"
 
37
#include "pack.h"
 
38
 
 
39
#ifndef WITH_CGRAPH
42
40
extern Agdict_t *agdictof(void *);
 
41
#endif
43
42
 
44
43
/* gvpack:
45
44
 * Input consists of graphs in dot format.
49
48
 * into a single output graph, ready to be sent to neato -s -n2.
50
49
 *  -m <i> specifies the margin, in points, about each graph.
51
50
 */
52
 
char *Info[] = {
53
 
    "gvpack",                   /* Program */
54
 
    VERSION,                    /* Version */
55
 
    BUILDDATE                   /* Build Date */
56
 
};
57
51
 
58
52
typedef struct {
59
53
    Dtlink_t link;
67
61
    int cnt;
68
62
} pair_t;
69
63
 
70
 
static int margin = 8;          /* Default margin in packing */
71
 
static boolean doSplines = TRUE;        /* Use edges in packing */
72
 
static pack_mode packMode = l_clust;    /* Default packing mode - use clusters */
73
64
static int verbose = 0;
74
65
static char **myFiles = 0;
75
66
static int nGraphs = 0;         /* Guess as to no. of graphs */
76
67
static FILE *outfp;             /* output; stdout by default */
77
 
static int kind = -1;           /* type of graph; -1 = undefined */
 
68
#ifndef WITH_CGRAPH
 
69
static int kind;                /* type of graph */
 
70
#else
 
71
static Agdesc_t kind;           /* type of graph */
 
72
#endif
78
73
static int G_cnt;               /* No. of -G arguments */
79
74
static int G_sz;                /* Storage size for -G arguments */
80
75
static attr_t *G_args;          /* Storage for -G arguments */
 
76
static int doPack;              /* Do packing if true */
81
77
 
82
78
#define NEWNODE(n) ((node_t*)ND_alg(n))
83
 
#define DOPACK     (packMode != l_undef)
84
79
 
85
80
static char *useString =
86
 
    "Usage: gvpack [-gnuv?] [-m<margin>] [-o<outf>] <files>\n\
 
81
    "Usage: gvpack [-gnuv?] [-m<margin>] {-array[_rc][n]] [-o<outf>] <files>\n\
87
82
  -n          - use node granularity\n\
88
83
  -g          - use graph granularity\n\
 
84
  -array*     - pack as array of graphs\n\
89
85
  -G<n>=<v>   - attach name/value attribute to output graph\n\
90
86
  -m<n>       - set margin to <n> points\n\
91
87
  -o<outfile> - write output to <outfile>\n\
144
140
    return 0;
145
141
}
146
142
 
147
 
/* setInt:
 
143
/* setUInt:
148
144
 * If arg is an integer, value is stored in v
149
 
 * and functions returns 0; otherwise, returns 1.
 
145
 * and function returns 0; otherwise, returns 1.
150
146
 */
151
 
static int setInt(int *v, char *arg)
 
147
static int setUInt(unsigned int *v, char *arg)
152
148
{
153
149
    char *p;
154
 
    int i;
 
150
    unsigned int i;
155
151
 
156
 
    i = (int) strtol(arg, &p, 10);
 
152
    i = (unsigned int) strtol(arg, &p, 10);
157
153
    if (p == arg) {
158
154
        fprintf(stderr, "Error: bad value in flag -%s - ignored\n",
159
155
                arg - 1);
163
159
    return 0;
164
160
}
165
161
 
 
162
#ifdef WITH_CGRAPH
 
163
static Agsym_t *agraphattr(Agraph_t *g, char *name, char *value)
 
164
{
 
165
    return agattr(g, AGRAPH, name, value);
 
166
}
 
167
 
 
168
static Agsym_t *agnodeattr(Agraph_t *g, char *name, char *value)
 
169
{
 
170
    return agattr(g, AGNODE, name, value);
 
171
}
 
172
 
 
173
static Agsym_t *agedgeattr(Agraph_t *g, char *name, char *value)
 
174
{
 
175
    return agattr(g, AGEDGE, name, value);
 
176
}
 
177
 
 
178
#endif
 
179
 
166
180
/* init:
167
181
 */
168
 
static void init(int argc, char *argv[])
 
182
static void init(int argc, char *argv[], pack_info* pinfo)
169
183
{
170
 
    int c;
 
184
    int c, len;
 
185
    char buf[BUFSIZ];
 
186
    char* bp;
171
187
 
 
188
#ifndef WITH_CGRAPH
172
189
    aginit();
173
 
    while ((c = getopt(argc, argv, ":ngvum:o:G:?")) != -1) {
 
190
#endif
 
191
    agnodeattr(NULL, "label", NODENAME_ESC);
 
192
    pinfo->mode = l_clust;
 
193
    pinfo->margin = CL_OFFSET;
 
194
    pinfo->doSplines = TRUE; /* Use edges in packing */
 
195
    pinfo->fixed = 0;
 
196
 
 
197
    opterr = 0;
 
198
    while ((c = getopt(argc, argv, ":na:gvum:o:G:")) != -1) {
174
199
        switch (c) {
 
200
        case 'a':
 
201
            len = strlen(optarg) + 2;
 
202
            if (len > BUFSIZ)
 
203
                bp = N_GNEW(len, char);
 
204
            else
 
205
                bp = buf;
 
206
            sprintf (bp, "a%s\n", optarg);
 
207
            parsePackModeInfo (bp, pinfo->mode, pinfo);
 
208
            if (bp != buf)
 
209
                free (bp);
 
210
            break;
175
211
        case 'n':
176
 
            packMode = l_node;
 
212
            pinfo->mode = l_node;
177
213
            break;
178
214
        case 'g':
179
 
            packMode = l_graph;
 
215
            pinfo->mode = l_graph;
180
216
            break;
181
217
        case 'm':
182
 
            setInt(&margin, optarg);
 
218
            setUInt(&pinfo->margin, optarg);
183
219
            break;
184
220
        case 'o':
185
221
            outfp = openFile(optarg, "w");
186
222
            break;
187
223
        case 'u':
188
 
            packMode = l_undef;
 
224
            pinfo->mode = l_undef;
189
225
            break;
190
226
        case 'G':
191
227
            if (*optarg)
227
263
    node_t *n;
228
264
    edge_t *e;
229
265
    int nG = agnnodes(g);
230
 
    attrsym_t *N_pos = agfindattr(g->proto->n, "pos");
231
 
    attrsym_t *N_pin = agfindattr(g->proto->n, "pin");
 
266
    attrsym_t *N_pos = agfindnodeattr(g, "pos");
 
267
    attrsym_t *N_pin = agfindnodeattr(g, "pin");
232
268
 
233
269
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
234
270
        neato_init_node(n);
245
281
 * libcommon. If fill is true, we use init_nop (neato -n) to
246
282
 * read in attributes relevant to the layout.
247
283
 */
248
 
static void init_graph(Agraph_t * g, boolean fill)
 
284
static void init_graph(Agraph_t * g, boolean fill, GVC_t* gvc)
249
285
{
250
286
    int d;
251
287
 
 
288
#ifdef WITH_CGRAPH
 
289
    aginit (g, AGRAPH, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
 
290
    aginit (g, AGNODE, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);
 
291
    aginit (g, AGEDGE, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);
 
292
#endif
 
293
    GD_gvc(g) = gvc;
252
294
    graph_init(g, FALSE);
253
 
    d = late_int(g, agfindattr(g, "dim"), 2, 2);
 
295
    d = late_int(g, agfindgraphattr(g, "dim"), 2, 2);
254
296
    if (d != 2) {
255
 
        fprintf(stderr, "Error: graph %s has dim = %d (!= 2)\n", g->name,
 
297
        fprintf(stderr, "Error: graph %s has dim = %d (!= 2)\n", agnameof(g),
256
298
                d);
257
299
        exit(1);
258
300
    }
267
309
 * Copy all attributes from old object to new. Assume
268
310
 * attributes have been initialized.
269
311
 */
 
312
#ifdef WITH_CGRAPH
 
313
static void cloneDfltAttrs(Agraph_t *old, Agraph_t *new, int kind)
 
314
{
 
315
    Agsym_t *a;
 
316
 
 
317
    for (a = agnxtattr(old, kind, 0); a; a =  agnxtattr(old, kind, a)) {
 
318
        agattr (new, kind, a->name, a->defval);
 
319
    }
 
320
}
 
321
static void cloneAttrs(void *old, void *new)
 
322
{
 
323
    int kind = AGTYPE(old);
 
324
    Agsym_t *a;
 
325
    Agraph_t *g = agroot(old);
 
326
 
 
327
    for (a = agnxtattr(g, kind, 0); a; a =  agnxtattr(g, kind, a)) {
 
328
        agset(new, a->name, agxget(old, a));
 
329
    }
 
330
}
 
331
#else
270
332
static void cloneAttrs(void *old, void *new)
271
333
{
272
334
    int j;
278
340
        agset(new, a->name, agxget(old, a->index));
279
341
    }
280
342
}
 
343
#endif
281
344
 
282
345
/* cloneEdge:
283
346
 * Note that here, and in cloneNode and cloneCluster,
299
362
static void cloneNode(Agnode_t * old, Agnode_t * new)
300
363
{
301
364
    cloneAttrs(old, new);
302
 
    ND_coord_i(new).x = POINTS(ND_pos(old)[0]);
303
 
    ND_coord_i(new).y = POINTS(ND_pos(old)[1]);
 
365
    ND_coord(new).x = POINTS(ND_pos(old)[0]);
 
366
    ND_coord(new).y = POINTS(ND_pos(old)[1]);
304
367
    ND_height(new) = ND_height(old);
305
 
    ND_ht_i(new) = ND_ht_i(old);
 
368
    ND_ht(new) = ND_ht(old);
306
369
    ND_width(new) = ND_width(old);
307
 
    ND_lw_i(new) = ND_lw_i(old);
308
 
    ND_rw_i(new) = ND_rw_i(old);
 
370
    ND_lw(new) = ND_lw(old);
 
371
    ND_rw(new) = ND_rw(old);
309
372
    ND_shape(new) = ND_shape(old);
310
373
    ND_shape_info(new) = ND_shape_info(old);
311
374
}
344
407
 * objp. If the attribute has already been defined and
345
408
 * has a different default, set default to "".
346
409
 */
 
410
#ifdef WITH_CGRAPH
 
411
static void fillDict(Dt_t * newdict, Agraph_t* g, int kind)
 
412
{
 
413
    Agsym_t *a;
 
414
    char *name;
 
415
    char *value;
 
416
    attr_t *rv;
 
417
 
 
418
    for (a = agnxtattr(g,kind,0); a; a = agnxtattr(g,kind,a)) {
 
419
        name = a->name;
 
420
        value = a->defval;
 
421
        rv = (attr_t *) dtmatch(newdict, name);
 
422
        if (!rv) {
 
423
            rv = NEW(attr_t);
 
424
            rv->name = name;
 
425
            rv->value = value;
 
426
            dtinsert(newdict, rv);
 
427
        } else if (strcmp(value, rv->value))
 
428
            rv->value = "";
 
429
    }
 
430
}
 
431
#else
347
432
static void fillDict(Dt_t * newdict, void *objp)
348
433
{
349
434
    int j;
367
452
            rv->value = "";
368
453
    }
369
454
}
 
455
#endif
370
456
 
371
457
/* fillGraph:
372
458
 * Use all the name-value entries in the dictionary d to define
401
487
 
402
488
    for (i = 0; i < cnt; i++) {
403
489
        g = gs[i];
 
490
#ifdef WITH_CGRAPH
 
491
        fillDict(g_attrs, g, AGRAPH);
 
492
        fillDict(n_attrs, g, AGNODE);
 
493
        fillDict(e_attrs, g, AGEDGE);
 
494
#else
404
495
        fillDict(g_attrs, g);
405
496
        fillDict(n_attrs, g->proto->n);
406
497
        fillDict(e_attrs, g->proto->e);
 
498
#endif
407
499
    }
408
500
 
409
501
    fillGraph(root, g_attrs, agraphattr);
420
512
static void cloneGraphAttr(Agraph_t * g, Agraph_t * ng)
421
513
{
422
514
    cloneAttrs(g, ng);
 
515
#ifdef WITH_CGRAPH
 
516
    cloneDfltAttrs(g, ng, AGNODE);
 
517
    cloneDfltAttrs(g, ng, AGEDGE);
 
518
#else
423
519
    cloneAttrs(g->proto->n, ng->proto->n);
424
520
    cloneAttrs(g->proto->e, ng->proto->e);
 
521
#endif
425
522
}
426
523
 
427
524
#ifdef UNIMPL
451
548
 * dictionary names and the old name. If the old name has not
452
549
 * been used, use it and add it to names. If it has been used,
453
550
 * create a new name using the old name and a number.
 
551
 * Note that returned string will immediately made into an agstring.
454
552
 */
455
553
static char *xName(Dt_t * names, char *oldname)
456
554
{
457
 
    char name[BUFSIZ];
 
555
    static char* name = NULL;
 
556
    static int namelen = 0;
458
557
    char *namep;
459
558
    pair_t *p;
 
559
    int len;
460
560
 
461
561
    p = (pair_t *) dtmatch(names, oldname);
462
562
    if (p) {
463
563
        p->cnt++;
 
564
        len = strlen(oldname) + 100; /* 100 for "_gv" and decimal no. */
 
565
        if (namelen < len) {
 
566
            if (name) free (name);
 
567
            name = N_NEW(len, char);
 
568
            namelen = len;
 
569
        }
464
570
        sprintf(name, "%s_gv%d", oldname, p->cnt);
465
571
        namep = name;
466
572
    } else {
474
580
 
475
581
#define MARK(e) (ED_alg(e) = e)
476
582
#define MARKED(e) (ED_alg(e))
477
 
#define ISCLUSTER(g) (!strncmp(g->name,"cluster",7))
 
583
#define ISCLUSTER(g) (!strncmp(agnameof(g),"cluster",7))
478
584
#define SETCLUST(g,h) (GD_alg(g) = h)
479
585
#define GETCLUST(g) ((Agraph_t*)GD_alg(g))
480
586
 
485
591
static void
486
592
cloneSubg(Agraph_t * g, Agraph_t * ng, Agsym_t * G_bb, Dt_t * gnames)
487
593
{
 
594
#ifndef WITH_CGRAPH
488
595
    graph_t *mg;
489
596
    edge_t *me;
490
597
    node_t *mn;
 
598
#endif
491
599
    node_t *n;
492
600
    node_t *nn;
493
601
    edge_t *e;
498
606
    Agraph_t *nsubg;
499
607
 
500
608
    cloneGraphAttr(g, ng);
501
 
    if (DOPACK)
 
609
    if (doPack)
 
610
#ifdef WITH_CGRAPH
 
611
        agxset(ng, G_bb, "");   /* Unset all subgraph bb */
 
612
#else
502
613
        agxset(ng, G_bb->index, "");    /* Unset all subgraph bb */
 
614
#endif
503
615
 
504
616
    /* clone subgraphs */
 
617
#ifdef WITH_CGRAPH
 
618
    for (subg = agfstsubg (g); subg; subg = agfstsubg (subg)) {
 
619
        nsubg = agsubg(ng, xName(gnames, agnameof(subg)), 1);
 
620
#else
505
621
    mg = g->meta_node->graph;
506
622
    for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
507
 
        mn = me->head;
 
623
        mn = aghead(me);
508
624
        subg = agusergraph(mn);
509
 
        nsubg = agsubg(ng, xName(gnames, subg->name));
 
625
        nsubg = agsubg(ng, xName(gnames, agnameof(subg)));
 
626
#endif
510
627
        cloneSubg(subg, nsubg, G_bb, gnames);
511
628
        /* if subgraphs are clusters, point to the new 
512
629
         * one so we can find it later.
518
635
    /* add remaining nodes */
519
636
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
520
637
        nn = NEWNODE(n);
521
 
        if (!agfindnode(ng, nn->name)) {
 
638
#ifndef WITH_CGRAPH
 
639
        if (!agfindnode(ng, agnameof(nn)))
522
640
            aginsert(ng, nn);
523
 
        }
 
641
#else
 
642
        agsubnode(ng, nn, 1);
 
643
#endif
524
644
    }
525
645
 
526
646
    /* add remaining edges. libgraph doesn't provide a way to find
530
650
        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
531
651
            if (MARKED(e))
532
652
                continue;
533
 
            nt = NEWNODE(e->tail);
534
 
            nh = NEWNODE(e->head);
 
653
            nt = NEWNODE(agtail(e));
 
654
            nh = NEWNODE(aghead(e));
 
655
#ifndef WITH_CGRAPH
535
656
            ne = agedge(ng, nt, nh);
 
657
#else
 
658
            ne = agedge(ng, nt, nh, NULL, 1);
 
659
            agbindrec (ne, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);
 
660
#endif
536
661
            cloneEdge(e, ne);
537
662
            MARK(e);
538
663
        }
593
718
 
594
719
    if (verbose)
595
720
        fprintf(stderr, "Creating clone graph\n");
 
721
#ifndef WITH_CGRAPH
596
722
    root = agopen("root", kind);
597
 
    GD_gvc(root) = gvc;
 
723
#else
 
724
    root = agopen("root", kind, &AgDefaultDisc);
 
725
#endif
598
726
    initAttrs(root, gs, cnt);
599
 
    G_bb = agfindattr(root, "bb");
600
 
    if (DOPACK) assert(G_bb);
 
727
    G_bb = agfindgraphattr(root, "bb");
 
728
    if (doPack) assert(G_bb);
601
729
 
602
730
    /* add command-line attributes */
603
731
    for (i = 0; i < G_cnt; i++) {
604
 
        rv = agfindattr(root, G_args[i].name);
 
732
        rv = agfindgraphattr(root, G_args[i].name);
605
733
        if (rv)
 
734
#ifndef WITH_CGRAPH
606
735
            agxset(root, rv->index, G_args[i].value);
607
736
        else
608
737
            agraphattr(root, G_args[i].name, G_args[i].value);
 
738
#else
 
739
            agxset(root, rv, G_args[i].value);
 
740
        else
 
741
            agattr(root, AGRAPH, G_args[i].name, G_args[i].value);
 
742
#endif
609
743
    }
610
744
 
611
745
    /* do common initialization. This will handle root's label. */
612
 
    init_graph(root, FALSE);
 
746
    init_graph(root, FALSE, gvc);
613
747
    State = GVSPLINES;
614
748
 
615
749
    gnames = dtopen(&pairdisc, Dtoset);
617
751
    for (i = 0; i < cnt; i++) {
618
752
        g = gs[i];
619
753
        if (verbose)
620
 
            fprintf(stderr, "Cloning graph %s\n", g->name);
 
754
            fprintf(stderr, "Cloning graph %s\n", agnameof(g));
621
755
        GD_n_cluster(root) += GD_n_cluster(g);
622
756
 
623
757
        /* Clone nodes, checking for node name conflicts */
624
758
        for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
625
 
            if (doWarn && agfindnode(root, n->name)) {
 
759
            if (doWarn && agfindnode(root, agnameof(n))) {
626
760
                fprintf(stderr,
627
761
                        "Warning: node %s in graph[%d] %s already defined\n",
628
 
                        n->name, i, g->name);
 
762
                        agnameof(n), i, agnameof(g));
629
763
                fprintf(stderr, "Some nodes will be renamed.\n");
630
764
                doWarn = FALSE;
631
765
            }
632
 
            np = agnode(root, xName(nnames, n->name));
 
766
#ifndef WITH_CGRAPH
 
767
            np = agnode(root, xName(nnames, agnameof(n)));
 
768
#else
 
769
            np = agnode(root, xName(nnames, agnameof(n)), 1);
 
770
            agbindrec (np, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);
 
771
#endif
633
772
            ND_alg(n) = np;
634
773
            cloneNode(n, np);
635
774
        }
636
775
 
637
776
        /* wrap the clone of g in a subgraph of root */
638
 
        subg = agsubg(root, xName(gnames, g->name));
 
777
#ifndef WITH_CGRAPH
 
778
        subg = agsubg(root, xName(gnames, agnameof(g)));
 
779
#else
 
780
        subg = agsubg(root, xName(gnames, agnameof(g)), 1);
 
781
#endif
639
782
        cloneSubg(g, subg, G_bb, gnames);
640
783
    }
641
784
    dtclose(gnames);
660
803
    return root;
661
804
}
662
805
 
 
806
#ifdef WITH_CGRAPH
 
807
static Agraph_t *gread(FILE * fp)
 
808
{
 
809
    return agread(fp, (Agdisc_t *) 0);
 
810
}
 
811
#else
 
812
static Agraph_t *gread(FILE * fp)
 
813
{
 
814
    return agread(fp);
 
815
}
 
816
#endif
 
817
 
663
818
/* readGraphs:
664
819
 * Read input, parse the graphs, use init_nop (neato -n) to
665
820
 * read in all attributes need for layout.
677
832
    ingraph_state ig;
678
833
    int cnt = 0;
679
834
    int sz = 0;
 
835
    int kindUnset = 1;
680
836
 
681
837
    /* set various state values */
682
838
    PSinputscale = POINTS_PER_INCH;
683
839
    Nop = 2;
684
840
 
685
 
    newIngraph(&ig, myFiles, agread);
 
841
    newIngraph(&ig, myFiles, gread);
686
842
    while ((g = nextGraph(&ig)) != 0) {
687
 
        GD_gvc(g) = gvc;
688
843
        if (verbose)
689
 
            fprintf(stderr, "Reading graph %s\n", g->name);
 
844
            fprintf(stderr, "Reading graph %s\n", agnameof(g));
690
845
        if (cnt >= sz) {
691
846
            sz += nGraphs;
692
847
            gs = ALLOC(sz, gs, Agraph_t *);
693
848
        }
694
 
        if (kind == -1)
 
849
#ifndef WITH_CGRAPH
 
850
        if (kindUnset) {
 
851
            kindUnset = 0;
695
852
            kind = g->kind;
 
853
        }
696
854
        else if ((kind & AGFLAG_DIRECTED) != AG_IS_DIRECTED(g)) {
697
855
            fprintf(stderr,
698
856
                    "Error: all graphs must be directed or undirected\n");
699
857
            exit(1);
700
858
        } else if (!AG_IS_STRICT(g))
701
859
            kind = g->kind;
702
 
        init_graph(g, DOPACK);
 
860
#else
 
861
        if (kindUnset) {
 
862
            kindUnset = 0;
 
863
            kind = g->desc;
 
864
        }
 
865
        else if (kind.directed != g->desc.directed) {
 
866
            fprintf(stderr,
 
867
                    "Error: all graphs must be directed or undirected\n");
 
868
            exit(1);
 
869
        } else if (!agisstrict(g))
 
870
            kind = g->desc;
 
871
#endif
 
872
        init_graph(g, doPack, gvc);
703
873
        gs[cnt++] = g;
704
874
    }
705
875
 
713
883
 * Compute the bounding box containing the graphs.
714
884
 * We can just use the bounding boxes of the graphs.
715
885
 */
716
 
box compBB(Agraph_t ** gs, int cnt)
 
886
boxf compBB(Agraph_t ** gs, int cnt)
717
887
{
718
 
    box bb, bb2;
 
888
    boxf bb, bb2;
719
889
    int i;
720
890
 
721
891
    bb = GD_bb(gs[0]);
740
910
    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
741
911
        fprintf(stderr, "%s\n", v->name);
742
912
        for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
743
 
            fprintf(stderr, "  %s -- %s\n", e->tail->name, e->head->name);
 
913
            fprintf(stderr, "  %s -- %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
744
914
        }
745
915
    }
746
916
}
754
924
 
755
925
    mg = g->meta_node->graph;
756
926
    for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
757
 
        mn = me->head;
 
927
        mn = aghead(me);
758
928
        subg = agusergraph(mn);
759
929
        dump(subg);
760
930
        fprintf(stderr, "====\n");
768
938
    Agraph_t *g;
769
939
    int cnt;
770
940
    pack_info pinfo;
771
 
    box bb;
772
941
    GVC_t * gvc;
773
942
 
774
 
    init(argc, argv);
775
 
 
776
 
    gvc = gvNEWcontext(Info, gvUsername());
 
943
    init(argc, argv, &pinfo);
 
944
 
 
945
    doPack = (pinfo.mode != l_undef);
 
946
 
 
947
    gvc = gvNEWcontext(lt_preloaded_symbols, DEMAND_LOADING);
777
948
    gs = readGraphs(&cnt, gvc);
778
949
    if (cnt == 0)
779
950
        exit(0);
780
951
 
781
952
    /* pack graphs */
782
 
    if (DOPACK) {
783
 
        pinfo.margin = margin;
784
 
        pinfo.doSplines = doSplines;
785
 
        pinfo.mode = packMode;
786
 
        pinfo.fixed = 0;
 
953
    if (doPack) {
787
954
        if (packGraphs(cnt, gs, 0, &pinfo)) {
788
955
            fprintf(stderr, "gvpack: packing of graphs failed.\n");
789
956
            exit(1);
794
961
    g = cloneGraph(gs, cnt, gvc);
795
962
 
796
963
    /* compute new top-level bb and set */
797
 
    if (DOPACK) {
798
 
        bb = compBB(gs, cnt);
799
 
        GD_bb(g) = bb;
 
964
    if (doPack) {
 
965
        GD_bb(g) = compBB(gs, cnt);
800
966
        dotneato_postprocess(g);
801
967
        attach_attrs(g);
802
968
    }