Graphviz  2.41.20170921.2350
attr.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include <cghdr.h>
15 
16 /*
17  * dynamic attributes
18  */
19 
20 /* to create a graph's data dictionary */
21 
22 #define MINATTR 4 /* minimum allocation */
23 
24 static void freesym(Dict_t * d, void * obj, Dtdisc_t * disc);
25 
27  (int) offsetof(Agsym_t, name), /* use symbol name as key */
28  -1,
29  (int) offsetof(Agsym_t, link),
30  NIL(Dtmake_f),
31  freesym,
32  NIL(Dtcompar_f),
33  NIL(Dthash_f)
34 };
35 
36 static char DataDictName[] = "_AG_datadict";
37 static void init_all_attrs(Agraph_t * g);
38 static Agdesc_t ProtoDesc = { 1, 0, 1, 0, 1, 1 };
39 static Agraph_t *ProtoGraph;
40 
42 {
43  Agdatadict_t *rv;
44  rv = (Agdatadict_t *) aggetrec(g, DataDictName, FALSE);
45  if (rv || !cflag)
46  return rv;
47  init_all_attrs(g);
48  rv = (Agdatadict_t *) aggetrec(g, DataDictName, FALSE);
49  return rv;
50 }
51 
52 Dict_t *agdictof(Agraph_t * g, int kind)
53 {
54  Agdatadict_t *dd;
55  Dict_t *dict;
56 
57  dd = agdatadict(g, FALSE);
58  if (dd)
59  switch (kind) {
60  case AGRAPH:
61  dict = dd->dict.g;
62  break;
63  case AGNODE:
64  dict = dd->dict.n;
65  break;
66  case AGINEDGE:
67  case AGOUTEDGE:
68  dict = dd->dict.e;
69  break;
70  default:
71  agerr(AGERR,"agdictof: unknown kind %d\n", kind);
72  dict = NIL(Dict_t *);
73  break;
74  } else
75  dict = NIL(Dict_t *);
76  return dict;
77 }
78 
79 Agsym_t *agnewsym(Agraph_t * g, char *name, char *value, int id, int kind)
80 {
81  Agsym_t *sym;
82  sym = agalloc(g, sizeof(Agsym_t));
83  sym->kind = kind;
84  sym->name = agstrdup(g, name);
85  sym->defval = agstrdup(g, value);
86  sym->id = id;
87  return sym;
88 }
89 
90 static void agcopydict(Dict_t * src, Dict_t * dest, Agraph_t * g, int kind)
91 {
92  Agsym_t *sym, *newsym;
93 
94  assert(dtsize(dest) == 0);
95  for (sym = (Agsym_t *) dtfirst(src); sym;
96  sym = (Agsym_t *) dtnext(src, sym)) {
97  newsym = agnewsym(g, sym->name, sym->defval, sym->id, kind);
98  newsym->print = sym->print;
99  newsym->fixed = sym->fixed;
100  dtinsert(dest, newsym);
101  }
102 }
103 
104 static Agdatadict_t *agmakedatadict(Agraph_t * g)
105 {
106  Agraph_t *par;
107  Agdatadict_t *parent_dd, *dd;
108 
109  dd = (Agdatadict_t *) agbindrec(g, DataDictName, sizeof(Agdatadict_t),
110  FALSE);
111  dd->dict.n = agdtopen(g, &AgDataDictDisc, Dttree);
112  dd->dict.e = agdtopen(g, &AgDataDictDisc, Dttree);
113  dd->dict.g = agdtopen(g, &AgDataDictDisc, Dttree);
114  if ((par = agparent(g))) {
115  parent_dd = agdatadict(par, FALSE);
116  assert(dd != parent_dd);
117  dtview(dd->dict.n, parent_dd->dict.n);
118  dtview(dd->dict.e, parent_dd->dict.e);
119  dtview(dd->dict.g, parent_dd->dict.g);
120  } else {
121  if (ProtoGraph && (g != ProtoGraph)) {
122  /* it's not ok to dtview here for several reasons. the proto
123  graph could change, and the sym indices don't match */
124  parent_dd = agdatadict(ProtoGraph, FALSE);
125  agcopydict(parent_dd->dict.n, dd->dict.n, g, AGNODE);
126  agcopydict(parent_dd->dict.e, dd->dict.e, g, AGEDGE);
127  agcopydict(parent_dd->dict.g, dd->dict.g, g, AGRAPH);
128  }
129  }
130  return dd;
131 }
132 
133 /* look up an attribute with possible viewpathing */
134 Agsym_t *agdictsym(Dict_t * dict, char *name)
135 {
136  Agsym_t key;
137  key.name = (char *) name;
138  return (Agsym_t *) dtsearch(dict, &key);
139 }
140 
141 /* look up attribute in local dictionary with no view pathing */
142 Agsym_t *aglocaldictsym(Dict_t * dict, char *name)
143 {
144  Agsym_t *rv;
145  Dict_t *view;
146 
147  view = dtview(dict, NIL(Dict_t *));
148  rv = agdictsym(dict, name);
149  dtview(dict, view);
150  return rv;
151 }
152 
153 Agsym_t *agattrsym(void *obj, char *name)
154 {
155  Agattr_t *data;
156  Agsym_t *rv;
157  char *arg = name;
158 
159  data = agattrrec((Agobj_t *) obj);
160  if (data)
161  rv = agdictsym(data->dict, arg);
162  else
163  rv = NILsym;
164  return rv;
165 }
166 
167 /* to create a graph's, node's edge's string attributes */
168 
169 char *AgDataRecName = "_AG_strdata";
170 
171 static int topdictsize(Agobj_t * obj)
172 {
173  Dict_t *d;
174 
175  d = agdictof(agroot(agraphof(obj)), AGTYPE(obj));
176  return d ? dtsize(d) : 0;
177 }
178 
179 /* g can be either the enclosing graph, or ProtoGraph */
180 static Agrec_t *agmakeattrs(Agraph_t * context, void *obj)
181 {
182  int sz;
183  Agattr_t *rec;
184  Agsym_t *sym;
185  Dict_t *datadict;
186 
187  rec = agbindrec(obj, AgDataRecName, sizeof(Agattr_t), FALSE);
188  datadict = agdictof(context, AGTYPE(obj));
189  assert(datadict);
190  if (rec->dict == NIL(Dict_t *)) {
191  rec->dict = agdictof(agroot(context), AGTYPE(obj));
192  /* don't malloc(0) */
193  sz = topdictsize(obj);
194  if (sz < MINATTR)
195  sz = MINATTR;
196  rec->str = agalloc(agraphof(obj), (size_t) sz * sizeof(char *));
197  /* doesn't call agxset() so no obj-modified callbacks occur */
198  for (sym = (Agsym_t *) dtfirst(datadict); sym;
199  sym = (Agsym_t *) dtnext(datadict, sym))
200  rec->str[sym->id] = agstrdup(agraphof(obj), sym->defval);
201  } else {
202  assert(rec->dict == datadict);
203  }
204  return (Agrec_t *) rec;
205 }
206 
207 static void freeattr(Agobj_t * obj, Agattr_t * attr)
208 {
209  int i, sz;
210  Agraph_t *g;
211 
212  g = agraphof(obj);
213  sz = topdictsize(obj);
214  for (i = 0; i < sz; i++)
215  agstrfree(g, attr->str[i]);
216  agfree(g, attr->str);
217 }
218 
219 static void freesym(Dict_t * d, void * obj, Dtdisc_t * disc)
220 {
221  Agsym_t *sym;
222 
223  NOTUSED(d);
224  sym = (Agsym_t *) obj;
225  NOTUSED(disc);
226  agstrfree(Ag_G_global, sym->name);
228  agfree(Ag_G_global, sym);
229 }
230 
231 Agattr_t *agattrrec(void *obj)
232 {
233  return (Agattr_t *) aggetrec(obj, AgDataRecName, FALSE);
234 }
235 
236 
237 static void addattr(Agraph_t * g, Agobj_t * obj, Agsym_t * sym)
238 {
239  Agattr_t *attr;
240 
241  attr = (Agattr_t *) agattrrec(obj);
242  assert(attr != NIL(Agattr_t *));
243  if (sym->id >= MINATTR)
244  attr->str = (char **) AGDISC(g, mem)->resize(AGCLOS(g, mem),
245  attr->str,
246  sym->id *
247  sizeof(char *),
248  (sym->id +
249  1) * sizeof(char *));
250  attr->str[sym->id] = agstrdup(g, sym->defval);
251  /* agmethod_upd(g,obj,sym); JCE and GN didn't like this. */
252 }
253 
254 
255 static Agsym_t *setattr(Agraph_t * g, int kind, char *name, char *value)
256 {
257  Agdatadict_t *dd;
258  Dict_t *ldict, *rdict;
259  Agsym_t *lsym, *psym, *rsym, *rv;
260  Agraph_t *root;
261  Agnode_t *n;
262  Agedge_t *e;
263 
264  assert(value);
265  root = agroot(g);
266  dd = agdatadict(g, TRUE); /* force initialization of string attributes */
267  ldict = agdictof(g, kind);
268  lsym = aglocaldictsym(ldict, name);
269  if (lsym) { /* update old local definition */
270  agstrfree(g, lsym->defval);
271  lsym->defval = agstrdup(g, value);
272  rv = lsym;
273  } else {
274  psym = agdictsym(ldict, name); /* search with viewpath up to root */
275  if (psym) { /* new local definition */
276  lsym = agnewsym(g, name, value, psym->id, kind);
277  dtinsert(ldict, lsym);
278  rv = lsym;
279  } else { /* new global definition */
280  rdict = agdictof(root, kind);
281  rsym = agnewsym(g, name, value, dtsize(rdict), kind);
282  dtinsert(rdict, rsym);
283  switch (kind) {
284  case AGRAPH:
285  agapply(root, (Agobj_t *) root, (agobjfn_t) addattr,
286  rsym, TRUE);
287  break;
288  case AGNODE:
289  for (n = agfstnode(root); n; n = agnxtnode(root, n))
290  addattr(g, (Agobj_t *) n, rsym);
291  break;
292  case AGINEDGE:
293  case AGOUTEDGE:
294  for (n = agfstnode(root); n; n = agnxtnode(root, n))
295  for (e = agfstout(root, n); e; e = agnxtout(root, e))
296  addattr(g, (Agobj_t *) e, rsym);
297  break;
298  }
299  rv = rsym;
300  }
301  }
302  if (rv && (kind == AGRAPH))
303  agxset(g, rv, value);
304  agmethod_upd(g, g, rv); /* JCE and GN wanted this */
305  return rv;
306 }
307 
308 static Agsym_t *getattr(Agraph_t * g, int kind, char *name)
309 {
310  Agsym_t *rv = 0;
311  Dict_t *dict;
312  dict = agdictof(g, kind);
313  if (dict)
314  rv = agdictsym(dict, name); /* viewpath up to root */
315  return rv;
316 }
317 
318 /*
319  * create or update an existing attribute and return its descriptor.
320  * if the new value is NIL(char*), this is only a search, no update.
321  * when a new attribute is created, existing graphs/nodes/edges
322  * receive its default value.
323  */
324 Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value)
325 {
326  Agsym_t *rv;
327 
328  if (g == 0) {
329  if (ProtoGraph == 0)
330  ProtoGraph = agopen(0, ProtoDesc, 0);
331  g = ProtoGraph;
332  }
333  if (value)
334  rv = setattr(g, kind, name, value);
335  else
336  rv = getattr(g, kind, name);
337  return rv;
338 }
339 
340 Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr)
341 {
342  Dict_t *d;
343  Agsym_t *rv;
344 
345  if ((d = agdictof(g, kind))) {
346  if (attr)
347  rv = (Agsym_t *) dtnext(d, attr);
348  else
349  rv = (Agsym_t *) dtfirst(d);
350  } else
351  rv = 0;
352  return rv;
353 }
354 
355 /* Create or delete attributes associated with an object */
356 
358 {
359  /* Agdatadict_t *dd; */
360  /* Agrec_t *attr; */
361  Agraph_t *context;
362 
363  g->desc.has_attrs = 1;
364  /* dd = */ agmakedatadict(g);
365  if (!(context = agparent(g)))
366  context = g;
367  /* attr = */ agmakeattrs(context, g);
368 }
369 
371 {
372  Agdatadict_t *dd;
373  Agattr_t *attr;
374 
375  Ag_G_global = g;
376  if ((attr = agattrrec(g))) {
377  freeattr((Agobj_t *) g, attr);
378  agdelrec(g, attr->h.name);
379  }
380 
381  if ((dd = agdatadict(g, FALSE))) {
382  if (agdtclose(g, dd->dict.n)) return 1;
383  if (agdtclose(g, dd->dict.e)) return 1;
384  if (agdtclose(g, dd->dict.g)) return 1;
385  agdelrec(g, dd->h.name);
386  }
387  return 0;
388 }
389 
391 {
392  Agattr_t *data;
393 
394  data = agattrrec(n);
395  if ((!data) || (!data->dict))
396  (void) agmakeattrs(g, n);
397 }
398 
400 {
401  Agattr_t *rec;
402 
403  if ((rec = agattrrec(n))) {
404  freeattr((Agobj_t *) n, rec);
405  agdelrec(n, AgDataRecName);
406  }
407 }
408 
410 {
411  Agattr_t *data;
412 
413  data = agattrrec(e);
414  if ((!data) || (!data->dict))
415  (void) agmakeattrs(g, e);
416 }
417 
419 {
420  Agattr_t *rec;
421 
422  if ((rec = agattrrec(e))) {
423  freeattr((Agobj_t *) e, rec);
424  agdelrec(e, AgDataRecName);
425  }
426 }
427 
428 char *agget(void *obj, char *name)
429 {
430  Agsym_t *sym;
431  Agattr_t *data;
432  char *rv;
433 
434  sym = agattrsym(obj, name);
435  if (sym == NILsym)
436  rv = 0; /* note was "", but this provides more info */
437  else {
438  data = agattrrec((Agobj_t *) obj);
439  rv = (char *) (data->str[sym->id]);
440  }
441  return rv;
442 }
443 
444 char *agxget(void *obj, Agsym_t * sym)
445 {
446  Agattr_t *data;
447  char *rv;
448 
449  data = agattrrec((Agobj_t *) obj);
450  assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
451  rv = (char *) (data->str[sym->id]);
452  return rv;
453 }
454 
455 int agset(void *obj, char *name, char *value)
456 {
457  Agsym_t *sym;
458  int rv;
459 
460  sym = agattrsym(obj, name);
461  if (sym == NILsym)
462  rv = FAILURE;
463  else
464  rv = agxset(obj, sym, value);
465  return rv;
466 }
467 
468 int agxset(void *obj, Agsym_t * sym, char *value)
469 {
470  Agraph_t *g;
471  Agobj_t *hdr;
472  Agattr_t *data;
473  Agsym_t *lsym;
474 
475  g = agraphof(obj);
476  hdr = (Agobj_t *) obj;
477  data = agattrrec(hdr);
478  assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
479  agstrfree(g, data->str[sym->id]);
480  data->str[sym->id] = agstrdup(g, value);
481  if (hdr->tag.objtype == AGRAPH) {
482  /* also update dict default */
483  Dict_t *dict;
484  dict = agdatadict(g, FALSE)->dict.g;
485  if ((lsym = aglocaldictsym(dict, sym->name))) {
486  agstrfree(g, lsym->defval);
487  lsym->defval = agstrdup(g, value);
488  } else {
489  lsym = agnewsym(g, sym->name, value, sym->id, AGTYPE(hdr));
490  dtinsert(dict, lsym);
491  }
492  }
493  agmethod_upd(g, obj, sym);
494  return SUCCESS;
495 }
496 
497 int agsafeset(void *obj, char *name, char *value, char *def)
498 {
499  Agsym_t *a;
500 
501  a = agattr(agraphof(obj), AGTYPE(obj), name, 0);
502  if (!a)
503  a = agattr(agraphof(obj), AGTYPE(obj), name, def);
504  return agxset(obj, a, value);
505 }
506 
507 
508 /*
509  * attach attributes to the already created graph objs.
510  * presumably they were already initialized, so we don't invoke
511  * any of the old methods.
512  */
513 static void init_all_attrs(Agraph_t * g)
514 {
515  Agraph_t *root;
516  Agnode_t *n;
517  Agedge_t *e;
518 
519  root = agroot(g);
520  agapply(root, (Agobj_t *) root, (agobjfn_t) agraphattr_init,
521  NIL(Agdisc_t *), TRUE);
522  for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
523  agnodeattr_init(g, n);
524  for (e = agfstout(root, n); e; e = agnxtout(root, e)) {
525  agedgeattr_init(g, e);
526  }
527  }
528 }
529 
530 /* agcopyattr:
531  * Assumes attributes have already been declared.
532  * Do not copy key attribute for edges, as this must be distinct.
533  * Returns non-zero on failure or if objects have different type.
534  */
535 int agcopyattr(void *oldobj, void *newobj)
536 {
537  Agraph_t *g;
538  Agsym_t *sym;
539  Agsym_t *newsym;
540  char* val;
541  char* nval;
542  int r = 1;
543 
544  g = agraphof(oldobj);
545  if (AGTYPE(oldobj) != AGTYPE(newobj))
546  return 1;
547  sym = 0;
548  while ((sym = agnxtattr(g, AGTYPE(oldobj), sym))) {
549  newsym = agattrsym(newobj, sym->name);
550  if (!newsym)
551  return 1;
552  val = agxget(oldobj, sym);
553  r = agxset(newobj, newsym, val);
554  /* FIX(?): Each graph has its own string cache, so a whole new refstr is possibly
555  * allocated. If the original was an html string, make sure the new one is as well.
556  * If cgraph goes to single string table, this can be removed.
557  */
558  if (aghtmlstr (val)) {
559  nval = agxget (newobj, newsym);
560  agmarkhtmlstr (nval);
561  }
562  }
563  return r;
564 }
void agnodeattr_init(Agraph_t *g, Agnode_t *n)
Definition: attr.c:390
int(* Dtcompar_f)(Dt_t *, void *, void *, Dtdisc_t *)
Definition: cdt.h:40
unsigned int(* Dthash_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:41
Definition: cgraph.h:388
CGRAPH_API Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
Definition: graph.c:44
void agraphattr_init(Agraph_t *g)
Definition: attr.c:357
Agsym_t * agattr(Agraph_t *g, int kind, char *name, char *value)
Definition: attr.c:324
void agmarkhtmlstr(char *s)
Definition: refstr.c:188
void *(* Dtmake_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:38
struct Agdatadict_s::@3 dict
#define SUCCESS
Definition: cghdr.h:62
CGRAPH_API int aghtmlstr(char *)
Definition: refstr.c:178
int agdtclose(Agraph_t *g, Dict_t *dict)
Definition: utils.c:79
char * defval
Definition: cgraph.h:327
Agsym_t * agdictsym(Dict_t *dict, char *name)
Definition: attr.c:134
Agdesc_t desc
Definition: cgraph.h:241
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
Definition: attr.c:340
Agrec_t h
Definition: cgraph.h:319
int agxset(void *obj, Agsym_t *sym, char *value)
Definition: attr.c:468
char * name
Definition: cgraph.h:326
CDT_API Dt_t * dtview(Dt_t *, Dt_t *)
#define assert(x)
Definition: cghdr.h:47
#define NOTUSED(var)
Definition: cghdr.h:54
Definition: cdt.h:80
#define dtfirst(d)
Definition: cdt.h:254
Agtag_t tag
Definition: cgraph.h:108
#define AGCLOS(g, d)
Definition: cghdr.h:67
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
CGRAPH_API Agraph_t * agroot(void *obj)
Definition: obj.c:169
CGRAPH_API Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:25
#define AGOUTEDGE
Definition: cgraph.h:102
char * name
Definition: cgraph.h:84
#define NILsym
Definition: cghdr.h:59
unsigned char kind
Definition: cgraph.h:329
Agdatadict_t * agdatadict(Agraph_t *g, int cflag)
Definition: attr.c:41
CGRAPH_API void agfree(Agraph_t *g, void *ptr)
Definition: mem.c:89
void agedgeattr_init(Agraph_t *g, Agedge_t *e)
Definition: attr.c:409
#define AGTYPE(obj)
Definition: cgraph.h:113
char * agget(void *obj, char *name)
Definition: attr.c:428
CGRAPH_API Agraph_t * agraphof(void *obj)
Definition: obj.c:185
#define AGDISC(g, d)
Definition: cghdr.h:66
unsigned char fixed
Definition: cgraph.h:330
int agset(void *obj, char *name, char *value)
Definition: attr.c:455
char ** str
Definition: cgraph.h:321
void agedgeattr_delete(Agedge_t *e)
Definition: attr.c:418
CGRAPH_API Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition: node.c:45
unsigned has_attrs
Definition: cgraph.h:157
#define NIL(t)
Definition: dthdr.h:13
int
Definition: grammar.c:1264
Agsym_t * agattrsym(void *obj, char *name)
Definition: attr.c:153
Dict_t * e
Definition: cgraph.h:337
#define dtsearch(d, o)
Definition: cdt.h:260
Agsym_t * agnewsym(Agraph_t *g, char *name, char *value, int id, int kind)
Definition: attr.c:79
unsigned objtype
Definition: cgraph.h:92
#define FAILURE
Definition: cghdr.h:63
CGRAPH_API Agraph_t * agparent(Agraph_t *g)
Definition: subg.c:85
#define dtnext(d, o)
Definition: cdt.h:255
Dtdisc_t AgDataDictDisc
Definition: attr.c:26
Dict_t * g
Definition: cgraph.h:337
CGRAPH_API int agstrfree(Agraph_t *, char *)
Definition: refstr.c:149
CGRAPH_API char * agstrdup(Agraph_t *, char *)
Definition: refstr.c:97
EXTERN Agraph_t * Ag_G_global
Definition: cghdr.h:78
CDT_API int dtsize(Dt_t *)
Definition: dtsize.c:12
CGRAPH_API Agnode_t * agfstnode(Agraph_t *g)
Definition: node.c:38
CGRAPH_API Agrec_t * aggetrec(void *obj, char *name, int move_to_front)
Definition: rec.c:34
int agsafeset(void *obj, char *name, char *value, char *def)
Definition: attr.c:497
Definition: cgraph.h:83
#define AGNODE
Definition: cgraph.h:101
Dict_t * agdictof(Agraph_t *g, int kind)
Definition: attr.c:52
int id
Definition: cgraph.h:328
#define dtinsert(d, o)
Definition: cdt.h:262
Agattr_t * agattrrec(void *obj)
Definition: attr.c:231
int agcopyattr(void *oldobj, void *newobj)
Definition: attr.c:535
char * AgDataRecName
Definition: attr.c:169
Dict_t * agdtopen(Agraph_t *g, Dtdisc_t *disc, Dtmethod_t *method)
Definition: utils.c:53
CGRAPH_API int agdelrec(void *obj, char *name)
Definition: rec.c:145
Agsym_t * aglocaldictsym(Dict_t *dict, char *name)
Definition: attr.c:142
CDT_API Dtmethod_t * Dttree
Definition: cdt.h:176
unsigned char print
Definition: cgraph.h:331
CGRAPH_API void * agalloc(Agraph_t *g, size_t size)
Definition: mem.c:62
void agmethod_upd(Agraph_t *g, void *obj, Agsym_t *sym)
Definition: obj.c:107
CGRAPH_API void * agbindrec(void *obj, char *name, unsigned int size, int move_to_front)
Definition: rec.c:86
Agrec_t h
Definition: cgraph.h:335
#define AGINEDGE
Definition: cgraph.h:103
Definition: cdt.h:99
void agnodeattr_delete(Agnode_t *n)
Definition: attr.c:399
char * agxget(void *obj, Agsym_t *sym)
Definition: attr.c:444
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:40
#define AGEDGE
Definition: cgraph.h:104
int agapply(Agraph_t *g, Agobj_t *obj, agobjfn_t fn, void *arg, int preorder)
Definition: apply.c:61
#define FALSE
Definition: cgraph.h:35
#define MINATTR
Definition: attr.c:22
Definition: legal.c:60
void(* agobjfn_t)(Agraph_t *g, Agobj_t *obj, void *arg)
Definition: cgraph.h:210
int agraphattr_delete(Agraph_t *g)
Definition: attr.c:370
#define AGRAPH
Definition: cgraph.h:100
Dict_t * dict
Definition: cgraph.h:320
#define TRUE
Definition: cgraph.h:38
Dict_t * n
Definition: cgraph.h:337