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.
22
/* to create a graph's data dictionary */
24
#define MINATTR 4 /* minimum allocation */
26
static void freesym(Dict_t *d, Void_t *obj, Dtdisc_t *disc);
28
Dtdisc_t AgDataDictDisc = {
29
(int)offsetof(Agsym_t,name), /* use symbol name as key */
31
(int)offsetof(Agsym_t,link),
38
static char DataDictName[] = "_AG_datadict";
39
static void init_all_attrs(Agraph_t *g);
41
Agdatadict_t * agdatadict(Agraph_t *g)
44
while ((rv = (Agdatadict_t*) aggetrec(g,DataDictName,FALSE))
45
== NIL(Agdatadict_t*)) init_all_attrs(g);
49
Dict_t *agdictof(Agraph_t *g, int 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;
64
static Agdatadict_t *agmakedatadict(Agraph_t *g)
67
Agdatadict_t *parent_dd,*dd;
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);
83
Agsym_t *agnewsym(Agraph_t *g, char *name, char *value, int id, int kind)
86
sym = agalloc(g,sizeof(Agsym_t));
88
sym->name = agstrdup(g,name);
89
sym->defval = agstrdup(g,value);
94
/* look up or update a value associated with an object. */
95
Agsym_t *agdictsym(Dict_t *dict, char *name)
98
key.name = (char*)name;
99
return (Agsym_t*)dtsearch(dict,&key);
102
/* look up attribute in local dictionary with no view pathing */
103
Agsym_t *aglocaldictsym(Dict_t *dict, char *name)
108
view = dtview(dict,NIL(Dict_t*));
109
rv = agdictsym(dict,name);
114
Agsym_t *agattrsym(void *obj, char *name)
118
data = agattrrec((Agobj_t*)obj);
119
return (data ? agdictsym(data->dict,name) : NILsym);
122
/* to create a graph's, node's edge's string attributes */
124
static char DataRecName[] = "_AG_strdata";
126
static Agrec_t *agmakeattrs(void *obj, int norecur)
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);
148
else {assert(rec->dict == datadict);}
149
return (Agrec_t*)rec;
152
static int topdictsize(Agobj_t *obj)
154
return dtsize(agdictof(agroot(agraphof(obj)),AGTYPE(obj)));
158
static void freeattr(Agobj_t *obj, Agattr_t *attr)
164
sz = topdictsize(obj);
165
for (i = 0; i < sz; i++) agstrfree(g,attr->str[i]);
169
static void freesym(Dict_t *d, Void_t *obj, Dtdisc_t *disc)
176
agstrfree(Ag_G_global,sym->name);
177
agstrfree(Ag_G_global,sym->defval);
178
agfree(Ag_G_global,sym);
181
Agattr_t *agattrrec(void *obj)
183
return (Agattr_t*) aggetrec(obj,DataRecName,FALSE);
187
static void addattr(Agobj_t *obj, Agsym_t *sym)
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. */
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.
209
Agsym_t *agattr(Agraph_t *g, int kind, char *name, char *value)
213
Dict_t *ldict,*rdict;
217
ldict = agdictof(g,kind);
218
lsym = aglocaldictsym(ldict,name);
221
/* this attr was previously defined in this graph */
223
agstrfree(g,lsym->defval);
224
lsym->defval = agstrdup(g,value);
227
else { /* not previously defined here */
228
if (value) { /* need to define */
229
rsym = agdictsym(ldict,name); /* viewpath up to root */
231
lsym = agnewsym(g,name,value,rsym->id,kind);
232
dtinsert(ldict,lsym);
234
else { /* just define globally */
235
rdict = agdictof(root,kind);
236
lsym = rsym = agnewsym(g,name,value,dtsize(rdict),kind);
237
dtinsert(rdict,rsym);
241
agapply(root,(Agobj_t*)root,(agobjfn_t)addattr,lsym,TRUE);
244
for (n = agfstnode(root); n; n = agnxtnode(n))
245
addattr((Agobj_t*)n,lsym);
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);
254
agmethod_upd(g,g,lsym); /* JCE and GN wanted this instead */
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
261
if (lsym && (kind == AGRAPH)) agxset(g, lsym, value);
265
Agsym_t *agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
270
d = agdictof(g,kind);
271
if (attr) rv = (Agsym_t*)dtnext(d,attr);
272
else rv = (Agsym_t*)dtfirst(d);
276
/* Create or delete attributes associated with an object */
278
void agraphattr_init(Agraph_t *g, int norecur)
280
/* Agdatadict_t *dd; */
283
g->desc.has_attrs = 1;
284
/* dd = */ agmakedatadict(g);
285
/* attr = */ agmakeattrs(g,norecur);
288
void agraphattr_delete(Agraph_t *g)
294
if ((attr = agattrrec(g))) {
295
freeattr((Agobj_t*)g,attr);
296
agdelrec(g,attr->h.name);
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);
307
void agnodeattr_init(Agnode_t *n, int norecur)
311
if (agattrrec(n) == NIL(Agattr_t*))
312
/* data = */ agmakeattrs(n, norecur);
315
void agnodeattr_delete(Agnode_t *n)
319
if ((rec = agattrrec(n))) {
320
freeattr((Agobj_t*)n,rec);
321
agdelrec(n,DataRecName);
325
void agedgeattr_init(Agedge_t *e, int norecur)
328
/* Agdatadict_t *def; */
332
if (agattrrec(e) == NIL(Agattr_t*)) {
333
/* def = */ agdatadict(g);
334
/* data = */ agmakeattrs(e,norecur);
338
void agedgeattr_delete(Agedge_t *e)
342
if ((rec = agattrrec(e))) {
343
freeattr((Agobj_t*)e,rec);
344
agdelrec(e,DataRecName);
348
char *agget(void *obj, char *name)
354
sym = agattrsym(obj,name);
355
if (sym == NILsym) rv = "";
357
data = agattrrec((Agobj_t *)obj);
358
rv = (char*)(data->str[sym->id]);
363
char *agxget(void *obj, Agsym_t *sym)
368
data = agattrrec((Agobj_t*)obj);
369
assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
370
rv = (char*)(data->str[sym->id]);
374
int agset(void *obj, char *name, char *value)
379
sym = agattrsym(obj,name);
380
if (sym == NILsym) rv = FAILURE;
381
else rv = agxset(obj,sym,value);
385
int agxset(void *obj, Agsym_t *sym, char *value)
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 */
401
dict = agdatadict(g)->dict.g;
402
if ((lsym = aglocaldictsym(dict,sym->name))) {
403
agstrfree(g,lsym->defval);
404
lsym->defval = agstrdup(g,value);
407
lsym = agnewsym(g,sym->name,value,sym->id,AGTYPE(hdr));
411
agmethod_upd(g,obj,sym);
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.
420
static void init_all_attrs(Agraph_t *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);