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

« back to all changes in this revision

Viewing changes to agraph/attr.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
/*
 
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.
 
9
*/
 
10
#pragma prototyped
 
11
 
 
12
#include        <aghdr.h>
 
13
 
 
14
#ifdef DMALLOC
 
15
#include "dmalloc.h"
 
16
#endif
 
17
 
 
18
/*
 
19
 * dynamic attributes
 
20
 */
 
21
 
 
22
/* to create a graph's data dictionary */
 
23
 
 
24
#define MINATTR 4       /* minimum allocation */
 
25
 
 
26
static void freesym(Dict_t *d, Void_t *obj, Dtdisc_t *disc);
 
27
 
 
28
Dtdisc_t AgDataDictDisc = {
 
29
        (int)offsetof(Agsym_t,name),    /* use symbol name as key */
 
30
        -1,
 
31
        (int)offsetof(Agsym_t,link),
 
32
        NIL(Dtmake_f),
 
33
        freesym,
 
34
        NIL(Dtcompar_f),
 
35
        NIL(Dthash_f)
 
36
};
 
37
 
 
38
static char DataDictName[] = "_AG_datadict";
 
39
static void init_all_attrs(Agraph_t *g);
 
40
 
 
41
Agdatadict_t * agdatadict(Agraph_t *g)
 
42
{
 
43
        Agdatadict_t    *rv;
 
44
        while ((rv = (Agdatadict_t*) aggetrec(g,DataDictName,FALSE))
 
45
                        == NIL(Agdatadict_t*)) init_all_attrs(g);
 
46
        return rv;
 
47
}
 
48
 
 
49
Dict_t *agdictof(Agraph_t *g, int kind)
 
50
{
 
51
        Agdatadict_t    *dd;
 
52
        Dict_t  *dict;
 
53
 
 
54
        dd = agdatadict(g);
 
55
        switch (kind) {
 
56
                case AGRAPH:  dict = dd->dict.g; break;
 
57
                case AGNODE:  dict = dd->dict.n; break;
 
58
                case AGINEDGE: case AGOUTEDGE:  dict = dd->dict.e; break;
 
59
                default: abort();
 
60
        }
 
61
        return dict;
 
62
}
 
63
 
 
64
static Agdatadict_t *agmakedatadict(Agraph_t *g)
 
65
{
 
66
        Agraph_t                *par;
 
67
        Agdatadict_t    *parent_dd,*dd;
 
68
 
 
69
        dd = (Agdatadict_t*)agbindrec(g,DataDictName,sizeof(Agdatadict_t),FALSE);
 
70
        dd->dict.n = agdtopen(g,&AgDataDictDisc,Dttree);
 
71
        dd->dict.e = agdtopen(g,&AgDataDictDisc,Dttree);
 
72
        dd->dict.g = agdtopen(g,&AgDataDictDisc,Dttree);
 
73
        if ((par = agparent(g))) {
 
74
                parent_dd = agdatadict(par);
 
75
                assert(dd != parent_dd);
 
76
                dtview(dd->dict.n,parent_dd->dict.n);
 
77
                dtview(dd->dict.e,parent_dd->dict.e);
 
78
                dtview(dd->dict.g,parent_dd->dict.g);
 
79
        }
 
80
        return dd;
 
81
}
 
82
 
 
83
Agsym_t *agnewsym(Agraph_t *g, char *name, char *value, int id, int kind)
 
84
{
 
85
        Agsym_t *sym;
 
86
        sym = agalloc(g,sizeof(Agsym_t));
 
87
        sym->kind = kind;
 
88
        sym->name = agstrdup(g,name);
 
89
        sym->defval = agstrdup(g,value);
 
90
        sym->id = id;
 
91
        return sym;
 
92
}
 
93
 
 
94
        /* look up or update a value associated with an object. */
 
95
Agsym_t *agdictsym(Dict_t *dict, char *name)
 
96
{
 
97
        Agsym_t                 key;
 
98
        key.name = (char*)name;
 
99
        return (Agsym_t*)dtsearch(dict,&key);
 
100
}
 
101
 
 
102
/* look up attribute in local dictionary with no view pathing */
 
103
Agsym_t *aglocaldictsym(Dict_t *dict, char *name)
 
104
{
 
105
        Agsym_t *rv;
 
106
        Dict_t  *view;
 
107
 
 
108
        view = dtview(dict,NIL(Dict_t*));
 
109
        rv = agdictsym(dict,name);
 
110
        dtview(dict,view);
 
111
        return rv;
 
112
}
 
113
 
 
114
Agsym_t *agattrsym(void *obj, char *name)
 
115
{
 
116
        Agattr_t                *data;
 
117
 
 
118
        data = agattrrec((Agobj_t*)obj);
 
119
        return (data ? agdictsym(data->dict,name) : NILsym);
 
120
}
 
121
 
 
122
/* to create a graph's, node's edge's string attributes */
 
123
 
 
124
static char DataRecName[] = "_AG_strdata";
 
125
 
 
126
static Agrec_t *agmakeattrs(void *obj, int norecur)
 
127
{
 
128
        int                     sz;
 
129
        Agattr_t        *rec;
 
130
        Agsym_t         *sym;
 
131
        Agraph_t        *g;
 
132
        Dict_t          *datadict;
 
133
 
 
134
        g = agraphof(obj);
 
135
        rec = agrealbindrec(obj,DataRecName,sizeof(Agattr_t),FALSE,norecur);
 
136
        datadict = agdictof(agroot(g),AGTYPE(obj));
 
137
        if (rec->dict == NIL(Dict_t*)) {
 
138
                rec->dict = datadict;
 
139
                /* don't malloc(0) */
 
140
                sz = dtsize(datadict);
 
141
                if (sz < MINATTR) sz = MINATTR;
 
142
                rec->str = agalloc(g,sz*sizeof(char*));
 
143
                /* doesn't call agxset() so no obj-modified callbacks occur */
 
144
                for (sym = (Agsym_t*) dtfirst(datadict); sym;
 
145
                        sym = (Agsym_t*) dtnext(datadict, sym))
 
146
                                rec->str[sym->id] = agstrdup(g,sym->defval);
 
147
        }
 
148
        else {assert(rec->dict == datadict);}
 
149
        return (Agrec_t*)rec;
 
150
}
 
151
 
 
152
static int topdictsize(Agobj_t *obj)
 
153
{
 
154
        return dtsize(agdictof(agroot(agraphof(obj)),AGTYPE(obj)));
 
155
}
 
156
 
 
157
 
 
158
static void freeattr(Agobj_t *obj, Agattr_t *attr)
 
159
{
 
160
        int                     i,sz;
 
161
        Agraph_t        *g;
 
162
 
 
163
        g = agraphof(obj);
 
164
        sz = topdictsize(obj);
 
165
        for (i = 0; i < sz; i++) agstrfree(g,attr->str[i]);
 
166
        agfree(g,attr->str);
 
167
}
 
168
 
 
169
static void freesym(Dict_t *d, Void_t *obj, Dtdisc_t *disc)
 
170
{
 
171
        Agsym_t *sym;
 
172
 
 
173
        NOTUSED(d);
 
174
        sym = (Agsym_t*)obj;
 
175
        NOTUSED(disc);
 
176
        agstrfree(Ag_G_global,sym->name);
 
177
        agstrfree(Ag_G_global,sym->defval);
 
178
        agfree(Ag_G_global,sym);
 
179
}
 
180
 
 
181
Agattr_t *agattrrec(void *obj)
 
182
{
 
183
        return (Agattr_t*) aggetrec(obj,DataRecName,FALSE);
 
184
}
 
185
 
 
186
 
 
187
static void addattr(Agobj_t *obj, Agsym_t *sym)
 
188
{
 
189
        Agattr_t                *attr;
 
190
        Agraph_t                *g;
 
191
 
 
192
        g = agraphof(obj);
 
193
        attr = (Agattr_t*)agattrrec(obj);
 
194
        assert (attr != NIL(Agattr_t*));
 
195
        if (sym->id >= MINATTR)
 
196
                attr->str = (char**) AGDISC(g,mem)->resize(AGCLOS(g,mem),
 
197
                        attr->str, sym->id * sizeof(char*), (sym->id + 1) * sizeof(char*));
 
198
        attr->str[sym->id] = agstrdup(g,sym->defval);
 
199
        /* agmethod_upd(g,obj,sym);  JCE and GN didn't like this. */
 
200
}
 
201
 
 
202
 
 
203
/*
 
204
 * create or update an existing attribute and return its descriptor.
 
205
 * if the new value is NIL(char*), this is only a search, no update.
 
206
 * when a new attribute is created, existing graphs/nodes/edges
 
207
 * receive its default value.
 
208
 */
 
209
Agsym_t *agattr(Agraph_t *g, int kind, char *name, char *value)
 
210
{
 
211
        Agraph_t                *root;
 
212
        Agsym_t                 *lsym,*rsym;
 
213
        Dict_t                  *ldict,*rdict;
 
214
        Agnode_t                *n;
 
215
        Agedge_t                *e;
 
216
 
 
217
        ldict = agdictof(g,kind);
 
218
        lsym = aglocaldictsym(ldict,name);
 
219
        root = agroot(g);
 
220
        if (lsym) {     
 
221
                /* this attr was previously defined in this graph */
 
222
                if (value) {
 
223
                        agstrfree(g,lsym->defval);
 
224
                        lsym->defval = agstrdup(g,value);
 
225
                }
 
226
        }
 
227
        else {  /* not previously defined here */
 
228
                if (value) {    /* need to define */
 
229
                        rsym = agdictsym(ldict,name);   /* viewpath up to root */
 
230
                        if (rsym) {
 
231
                                lsym = agnewsym(g,name,value,rsym->id,kind);
 
232
                                dtinsert(ldict,lsym);
 
233
                        }
 
234
                        else {   /* just define globally */
 
235
                                rdict = agdictof(root,kind);
 
236
                                lsym = rsym = agnewsym(g,name,value,dtsize(rdict),kind);
 
237
                                dtinsert(rdict,rsym);
 
238
 
 
239
                                switch(kind) {
 
240
                                        case AGRAPH:
 
241
                                                agapply(root,(Agobj_t*)root,(agobjfn_t)addattr,lsym,TRUE);
 
242
                                                break;
 
243
                                        case AGNODE:
 
244
                                                for (n = agfstnode(root); n; n = agnxtnode(n))
 
245
                                                        addattr((Agobj_t*)n,lsym);
 
246
                                                break;
 
247
                                        case AGINEDGE: case AGOUTEDGE:
 
248
                                                for (n = agfstnode(root); n; n = agnxtnode(n))
 
249
                                                        for (e = agfstout(n); e; e = agnxtout(e))
 
250
                                                                addattr((Agobj_t*)e,lsym);
 
251
                                                break;
 
252
                                }
 
253
                        }
 
254
                        agmethod_upd(g,g,lsym);  /* JCE and GN wanted this instead */
 
255
                }
 
256
        }
 
257
        /* in graphs, defaults and actual values are always the same.
 
258
         * see also agxset() where graph attrs are handled.  therefore
 
259
         * agxset() must not call agattr() in its implementation 
 
260
         */
 
261
        if (lsym && (kind == AGRAPH)) agxset(g, lsym, value);
 
262
        return lsym;
 
263
}
 
264
 
 
265
Agsym_t *agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
 
266
{
 
267
        Dict_t  *d;
 
268
        Agsym_t *rv;
 
269
 
 
270
        d = agdictof(g,kind);
 
271
        if (attr) rv = (Agsym_t*)dtnext(d,attr);
 
272
        else rv = (Agsym_t*)dtfirst(d);
 
273
        return rv;
 
274
}
 
275
 
 
276
/* Create or delete attributes associated with an object */
 
277
 
 
278
void agraphattr_init(Agraph_t *g, int norecur)
 
279
{
 
280
        /* Agdatadict_t *dd; */
 
281
        /* Agrec_t                      *attr; */
 
282
 
 
283
        g->desc.has_attrs = 1;
 
284
        /* dd = */ agmakedatadict(g);
 
285
        /* attr = */ agmakeattrs(g,norecur);
 
286
}
 
287
 
 
288
void agraphattr_delete(Agraph_t *g)
 
289
{
 
290
        Agdatadict_t    *dd;
 
291
        Agattr_t                *attr;
 
292
 
 
293
        Ag_G_global = g;
 
294
        if ((attr = agattrrec(g))) {
 
295
                freeattr((Agobj_t*)g,attr);
 
296
                agdelrec(g,attr->h.name);
 
297
        }
 
298
 
 
299
        if ((dd = agdatadict(g))) {
 
300
                agdtclose(g,dd->dict.n);
 
301
                agdtclose(g,dd->dict.e);
 
302
                agdtclose(g,dd->dict.g);
 
303
                agdelrec(g,dd->h.name);
 
304
        }
 
305
}
 
306
 
 
307
void agnodeattr_init(Agnode_t *n, int norecur)
 
308
{
 
309
        /* Agrec_t                      *data; */
 
310
 
 
311
        if (agattrrec(n) == NIL(Agattr_t*))
 
312
                /* data = */ agmakeattrs(n, norecur);
 
313
}
 
314
 
 
315
void agnodeattr_delete(Agnode_t *n)
 
316
{
 
317
        Agattr_t                *rec;
 
318
 
 
319
        if ((rec = agattrrec(n))) {
 
320
                freeattr((Agobj_t*)n,rec);
 
321
                agdelrec(n,DataRecName);
 
322
        }
 
323
}
 
324
 
 
325
void agedgeattr_init(Agedge_t *e, int norecur)
 
326
{
 
327
        /* Agrec_t                      *data; */
 
328
        /* Agdatadict_t *def; */
 
329
        Agraph_t                *g;
 
330
 
 
331
        g = agraphof(e);
 
332
        if (agattrrec(e) == NIL(Agattr_t*)) {
 
333
                /* def = */ agdatadict(g);
 
334
                /* data = */ agmakeattrs(e,norecur);
 
335
        }
 
336
}
 
337
 
 
338
void agedgeattr_delete(Agedge_t *e)
 
339
{
 
340
        Agattr_t                *rec;
 
341
 
 
342
        if ((rec = agattrrec(e))) {
 
343
                freeattr((Agobj_t*)e,rec);
 
344
                agdelrec(e,DataRecName);
 
345
        }
 
346
}
 
347
 
 
348
char *agget(void *obj, char *name)
 
349
{
 
350
        Agsym_t                 *sym;
 
351
        Agattr_t                *data;
 
352
        char                    *rv;
 
353
 
 
354
        sym = agattrsym(obj,name);
 
355
        if (sym == NILsym) rv = "";
 
356
        else {
 
357
                data = agattrrec((Agobj_t *)obj);
 
358
                rv = (char*)(data->str[sym->id]);
 
359
        }
 
360
        return rv;
 
361
}
 
362
 
 
363
char *agxget(void *obj, Agsym_t *sym)
 
364
{
 
365
        Agattr_t        *data;
 
366
        char            *rv;
 
367
 
 
368
        data = agattrrec((Agobj_t*)obj);
 
369
        assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
 
370
        rv = (char*)(data->str[sym->id]);
 
371
        return rv;
 
372
}
 
373
 
 
374
int agset(void *obj, char *name, char *value)
 
375
{
 
376
        Agsym_t         *sym;
 
377
        int                     rv;
 
378
 
 
379
        sym = agattrsym(obj,name);
 
380
        if (sym == NILsym) rv = FAILURE;
 
381
        else rv = agxset(obj,sym,value);
 
382
        return rv;
 
383
}
 
384
 
 
385
int agxset(void *obj, Agsym_t *sym, char *value)
 
386
{
 
387
        Agraph_t        *g;
 
388
        Agobj_t         *hdr;
 
389
        Agattr_t        *data;
 
390
        Agsym_t         *lsym;
 
391
 
 
392
        g = agraphof(obj);
 
393
        hdr = (Agobj_t *)obj;
 
394
        data = agattrrec(hdr);
 
395
        assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
 
396
        agstrfree(g,data->str[sym->id]);
 
397
        data->str[sym->id] = agstrdup(g,value);
 
398
        if (hdr->tag.objtype == AGRAPH) {
 
399
                /* also update dict default */
 
400
                Dict_t  *dict;
 
401
                dict = agdatadict(g)->dict.g;
 
402
                if ((lsym = aglocaldictsym(dict,sym->name))) {
 
403
                        agstrfree(g,lsym->defval);
 
404
                        lsym->defval = agstrdup(g,value);
 
405
                }
 
406
                else {
 
407
                        lsym = agnewsym(g,sym->name,value,sym->id,AGTYPE(hdr));
 
408
                        dtinsert(dict,lsym);
 
409
                }
 
410
        }
 
411
        agmethod_upd(g,obj,sym);
 
412
        return SUCCESS;
 
413
}
 
414
 
 
415
/*
 
416
 * here we are attaching attributes to the already created graph objs.
 
417
 * presumably they were already initialized, so we don't invoke any
 
418
 * of the old methods.
 
419
 */
 
420
static void init_all_attrs(Agraph_t *g)
 
421
{
 
422
        Agraph_t        *root;
 
423
        Agnode_t        *n;
 
424
        Agedge_t        *e;
 
425
 
 
426
        root = agroot(g);
 
427
        agapply(root,(Agobj_t*)root,(agobjfn_t)agraphattr_init,NIL(Agdisc_t*),TRUE);
 
428
        for (n = agfstnode(root); n; n = agnxtnode(n)) {
 
429
                agnodeattr_init(n, FALSE);
 
430
                for (e = agfstout(n); e; e = agnxtout(e)) {
 
431
                        agedgeattr_init(e, FALSE);
 
432
                }
 
433
        }
 
434
}