Graphviz  2.41.20170921.2350
edge.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 #define IN_SET FALSE
17 #define OUT_SET TRUE
18 #define ID_ORDER TRUE
19 #define SEQ_ORDER FALSE
20 
21 static Agtag_t Tag; /* to silence warnings about initialization */
22 
23 
24 /* return first outedge of <n> */
26 {
27  Agsubnode_t *sn;
28  Agedge_t *e = NILedge;
29 
30  sn = agsubrep(g, n);
31  if (sn) {
32  dtrestore(g->e_seq, sn->out_seq);
33  e = (Agedge_t *) dtfirst(g->e_seq);
34  sn->out_seq = dtextract(g->e_seq);
35  }
36  return e;
37 }
38 
39 /* return outedge that follows <e> of <n> */
41 {
42  Agnode_t *n;
43  Agsubnode_t *sn;
44  Agedge_t *f = NILedge;
45 
46  n = AGTAIL(e);
47  sn = agsubrep(g, n);
48  if (sn) {
49  dtrestore(g->e_seq, sn->out_seq);
50  f = (Agedge_t *) dtnext(g->e_seq, e);
51  sn->out_seq = dtextract(g->e_seq);
52  }
53  return f;
54 }
55 
57 {
58  Agsubnode_t *sn;
59  Agedge_t *e = NILedge;
60 
61  sn = agsubrep(g, n);
62  if (sn) {
63  dtrestore(g->e_seq, sn->in_seq);
64  e = (Agedge_t *) dtfirst(g->e_seq);
65  sn->in_seq = dtextract(g->e_seq);
66  }
67  return e;
68 }
69 
71 {
72  Agnode_t *n;
73  Agsubnode_t *sn;
74  Agedge_t *f = NILedge;
75 
76  n = AGHEAD(e);
77  sn = agsubrep(g, n);
78  if (sn) {
79  dtrestore(g->e_seq, sn->in_seq);
80  f = (Agedge_t *) dtnext(g->e_seq, e);
81  sn->in_seq = dtextract(g->e_seq);
82  }
83  return f;
84 }
85 
87 {
88  Agedge_t *rv;
89  rv = agfstout(g, n);
90  if (rv == NILedge)
91  rv = agfstin(g, n);
92  return rv;
93 }
94 
96 {
97  Agedge_t *rv;
98 
99  if (AGTYPE(e) == AGOUTEDGE) {
100  rv = agnxtout(g, e);
101  if (rv == NILedge) {
102  do {
103  rv = !rv ? agfstin(g, n) : agnxtin(g,rv);
104  } while (rv && (rv->node == n));
105  }
106  } else {
107  do {
108  rv = agnxtin(g, e); /* so that we only see each edge once, */
109  e = rv;
110  } while (rv && (rv->node == n)); /* ignore loops as in-edges */
111  }
112  return rv;
113 }
114 
115 /* internal edge set lookup */
116 static Agedge_t *agfindedge_by_key(Agraph_t * g, Agnode_t * t, Agnode_t * h,
117  Agtag_t key)
118 {
119  Agedge_t *e, template;
120  Agsubnode_t *sn;
121 
122  if ((t == NILnode) || (h == NILnode))
123  return NILedge;
124  template.base.tag = key;
125  template.node = t; /* guess that fan-in < fan-out */
126  sn = agsubrep(g, h);
127  if (!sn) e = 0;
128  else {
129 #if 0
130  if (t != h) {
131 #endif
132  dtrestore(g->e_id, sn->in_id);
133  e = (Agedge_t *) dtsearch(g->e_id, &template);
134  sn->in_id = dtextract(g->e_id);
135 #if 0
136  } else { /* self edge */
137  dtrestore(g->e_id, sn->out_id);
138  e = (Agedge_t *) dtsearch(g->e_id, &template);
139  sn->out_id = dtextract(g->e_id);
140  }
141 #endif
142  }
143  return e;
144 }
145 
146 static Agedge_t *agfindedge_by_id(Agraph_t * g, Agnode_t * t, Agnode_t * h,
147  IDTYPE id)
148 {
149  Agtag_t tag;
150 
151  tag = Tag;
152  tag.objtype = AGEDGE;
153  tag.id = id;
154  return agfindedge_by_key(g, t, h, tag);
155 }
156 
158 {
159  Agsubnode_t *sn, template;
160 
161  if (g == n->root) sn = &(n->mainsub);
162  else {
163  template.node = n;
164  sn = dtsearch(g->n_id, &template);
165  }
166  return sn;
167 }
168 
169 static void ins(Dict_t * d, Dtlink_t ** set, Agedge_t * e)
170 {
171  dtrestore(d, *set);
172  dtinsert(d, e);
173  *set = dtextract(d);
174 }
175 
176 static void del(Dict_t * d, Dtlink_t ** set, Agedge_t * e)
177 {
178  void *x;
179  dtrestore(d, *set);
180  x = dtdelete(d, e);
181  assert(x);
182  *set = dtextract(d);
183 }
184 
185 static void installedge(Agraph_t * g, Agedge_t * e)
186 {
187  Agnode_t *t, *h;
188  Agedge_t *out, *in;
189  Agsubnode_t *sn;
190 
191  out = AGMKOUT(e);
192  in = AGMKIN(e);
193  t = agtail(e);
194  h = aghead(e);
195  while (g) {
196  if (agfindedge_by_key(g, t, h, AGTAG(e))) break;
197  sn = agsubrep(g, t);
198  ins(g->e_seq, &sn->out_seq, out);
199  ins(g->e_id, &sn->out_id, out);
200  sn = agsubrep(g, h);
201  ins(g->e_seq, &sn->in_seq, in);
202  ins(g->e_id, &sn->in_id, in);
203  g = agparent(g);
204  }
205 }
206 
207 static void subedge(Agraph_t * g, Agedge_t * e)
208 {
209  installedge(g, e);
210  /* might an init method call be needed here? */
211 }
212 
213 static Agedge_t *newedge(Agraph_t * g, Agnode_t * t, Agnode_t * h,
214  IDTYPE id)
215 {
216  Agedgepair_t *e2;
217  Agedge_t *in, *out;
218  int seq;
219 
220  (void)agsubnode(g,t,TRUE);
221  (void)agsubnode(g,h,TRUE);
222  e2 = (Agedgepair_t *) agalloc(g, sizeof(Agedgepair_t));
223  in = &(e2->in);
224  out = &(e2->out);
225  seq = agnextseq(g, AGEDGE);
226  AGTYPE(in) = AGINEDGE;
227  AGTYPE(out) = AGOUTEDGE;
228  AGID(in) = AGID(out) = id;
229  AGSEQ(in) = AGSEQ(out) = seq;
230  in->node = t;
231  out->node = h;
232 
233  installedge(g, out);
234  if (g->desc.has_attrs) {
235  (void) agbindrec(out, AgDataRecName, sizeof(Agattr_t), FALSE);
236  agedgeattr_init(g, out);
237  }
238  agmethod_init(g, out);
239  return out;
240 }
241 
242 /* edge creation predicate */
243 static int ok_to_make_edge(Agraph_t * g, Agnode_t * t, Agnode_t * h)
244 {
245  Agtag_t key;
246 
247  /* protect against self, multi-edges in strict graphs */
248  if (agisstrict(g)) {
249  key = Tag;
250  key.objtype = 0; /* wild card */
251  if (agfindedge_by_key(g, t, h, key))
252  return FALSE;
253  }
254  if (g->desc.no_loop && (t == h)) /* simple graphs */
255  return FALSE;
256  return TRUE;
257 }
258 
260  IDTYPE id, int cflag)
261 {
262  Agraph_t *root;
263  Agedge_t *e;
264 
265  e = agfindedge_by_id(g, t, h, id);
266  if ((e == NILedge) && agisundirected(g))
267  e = agfindedge_by_id(g, h, t, id);
268  if ((e == NILedge) && cflag && ok_to_make_edge(g, t, h)) {
269  root = agroot(g);
270  if ((g != root) && ((e = agfindedge_by_id(root, t, h, id)))) {
271  subedge(g, e); /* old */
272  } else {
273  if (agallocid(g, AGEDGE, id)) {
274  e = newedge(g, t, h, id); /* new */
275  }
276  }
277  }
278  return e;
279 }
280 
281 Agedge_t *agedge(Agraph_t * g, Agnode_t * t, Agnode_t * h, char *name,
282  int cflag)
283 {
284  Agedge_t *e;
285  IDTYPE my_id;
286  int have_id;
287 
288  have_id = agmapnametoid(g, AGEDGE, name, &my_id, FALSE);
289  if (have_id || ((name == NILstr) && (NOT(cflag) || agisstrict(g)))) {
290  /* probe for pre-existing edge */
291  Agtag_t key;
292  key = Tag;
293  if (have_id) {
294  key.id = my_id;
295  key.objtype = AGEDGE;
296  } else {
297  key.id = key.objtype = 0;
298  }
299 
300  /* might already exist locally */
301  e = agfindedge_by_key(g, t, h, key);
302  if ((e == NILedge) && agisundirected(g))
303  e = agfindedge_by_key(g, h, t, key);
304  if (e)
305  return e;
306  if (cflag) {
307  e = agfindedge_by_key(agroot(g), t, h, key);
308  if ((e == NILedge) && agisundirected(g))
309  e = agfindedge_by_key(agroot(g), h, t, key);
310  if (e) {
311  subedge(g,e);
312  return e;
313  }
314  }
315  }
316 
317  if (cflag && ok_to_make_edge(g, t, h)
318  && agmapnametoid(g, AGEDGE, name, &my_id, TRUE)) { /* reserve id */
319  e = newedge(g, t, h, my_id);
320  agregister(g, AGEDGE, e); /* register new object in external namespace */
321  }
322  else
323  e = NILedge;
324  return e;
325 }
326 
327 void agdeledgeimage(Agraph_t * g, Agedge_t * e, void *ignored)
328 {
329  Agedge_t *in, *out;
330  Agnode_t *t, *h;
331  Agsubnode_t *sn;
332 
333  NOTUSED(ignored);
334  if (AGTYPE(e) == AGINEDGE) {
335  in = e;
336  out = AGIN2OUT(e);
337  } else {
338  out = e;
339  in = AGOUT2IN(e);
340  }
341  t = in->node;
342  h = out->node;
343  sn = agsubrep(g, t);
344  del(g->e_seq, &sn->out_seq, out);
345  del(g->e_id, &sn->out_id, out);
346  sn = agsubrep(g, h);
347  del(g->e_seq, &sn->in_seq, in);
348  del(g->e_id, &sn->in_id, in);
349 #ifdef DEBUG
350  for (e = agfstin(g,h); e; e = agnxtin(g,e))
351  assert(e != in);
352  for (e = agfstout(g,t); e; e = agnxtout(g,e))
353  assert(e != out);
354 #endif
355 }
356 
358 {
359  e = AGMKOUT(e);
360  if (agfindedge_by_key(g, agtail(e), aghead(e), AGTAG(e)) == NILedge)
361  return FAILURE;
362 
363  if (g == agroot(g)) {
364  if (g->desc.has_attrs)
366  agmethod_delete(g, e);
367  agrecclose((Agobj_t *) e);
368  agfreeid(g, AGEDGE, AGID(e));
369  }
370  if (agapply (g, (Agobj_t *) e, (agobjfn_t) agdeledgeimage, NILedge, FALSE) == SUCCESS) {
371  if (g == agroot(g))
372  agfree(g, e);
373  return SUCCESS;
374  } else
375  return FAILURE;
376 }
377 
378 Agedge_t *agsubedge(Agraph_t * g, Agedge_t * e, int cflag)
379 {
380  Agnode_t *t, *h;
381  Agedge_t *rv;
382 
383  rv = NILedge;
384  t = agsubnode(g, AGTAIL(e), cflag);
385  h = agsubnode(g, AGHEAD(e), cflag);
386  if (t && h) {
387  rv = agfindedge_by_key(g, t, h, AGTAG(e));
388  if (cflag && (rv == NILedge)) {
389 #ifdef OLD_OBSOLETE
390  rv = agfindedge_by_id(g, t, h, AGID(e));
391  if (!rv)
392  rv = newedge(g, t, h, AGID(e));
393 #else
394  installedge(g, e);
395  rv = e;
396 #endif
397  }
398  if (rv && (AGTYPE(rv) != AGTYPE(e)))
399  rv = AGOPP(rv);
400  }
401  return rv;
402 }
403 
404 /* edge comparison. AGTYPE(e) == 0 means ID is a wildcard. */
405 int agedgeidcmpf(Dict_t * d, void *arg_e0, void *arg_e1, Dtdisc_t * disc)
406 {
407  Agedge_t *e0, *e1;
408 
409  NOTUSED(d);
410  e0 = arg_e0;
411  e1 = arg_e1;
412  NOTUSED(disc);
413 
414  if (AGID(e0->node) < AGID(e1->node)) return -1;
415  if (AGID(e0->node) > AGID(e1->node)) return 1;
416  /* same node */
417  if ((AGTYPE(e0) != 0) && (AGTYPE(e1) != 0)) {
418  if (AGID(e0) < AGID(e1)) return -1;
419  if (AGID(e0) > AGID(e1)) return 1;
420  }
421  return 0;
422 }
423 
424 /* edge comparison. for ordered traversal. */
425 int agedgeseqcmpf(Dict_t * d, void *arg_e0, void *arg_e1, Dtdisc_t * disc)
426 {
427  Agedge_t *e0, *e1;
428 
429  NOTUSED(d);
430  e0 = arg_e0;
431  e1 = arg_e1;
432  NOTUSED(disc);
433  assert(arg_e0 && arg_e1);
434 
435  if (e0->node != e1->node) {
436  if (AGSEQ(e0->node) < AGSEQ(e1->node)) return -1;
437  if (AGSEQ(e0->node) > AGSEQ(e1->node)) return 1;
438  }
439  else {
440  if (AGSEQ(e0) < AGSEQ(e1)) return -1;
441  if (AGSEQ(e0) > AGSEQ(e1)) return 1;
442  }
443  return 0;
444 }
445 
446 /* indexing for ordered traversal */
448  0, /* pass object ptr */
449  0, /* size (ignored) */
450  offsetof(Agedge_t,seq_link),/* use internal links */
451  NIL(Dtmake_f),
452  NIL(Dtfree_f),
454  NIL(Dthash_f),
455  agdictobjmem,
456  NIL(Dtevent_f)
457 };
458 
460  0, /* pass object ptr */
461  0, /* size (ignored) */
462  -1, /* use external holder objects */
463  NIL(Dtmake_f),
464  NIL(Dtfree_f),
466  NIL(Dthash_f),
467  agdictobjmem,
468  NIL(Dtevent_f)
469 };
470 
471 /* indexing for random search */
473  0, /* pass object ptr */
474  0, /* size (ignored) */
475  offsetof(Agedge_t,id_link), /* use internal links */
476  NIL(Dtmake_f),
477  NIL(Dtfree_f),
478  agedgeidcmpf,
479  NIL(Dthash_f),
480  agdictobjmem,
481  NIL(Dtevent_f)
482 };
483 
485  0, /* pass object ptr */
486  0, /* size (ignored) */
487  -1, /* use external holder objects */
488  NIL(Dtmake_f),
489  NIL(Dtfree_f),
490  agedgeidcmpf,
491  NIL(Dthash_f),
492  agdictobjmem,
493  NIL(Dtevent_f)
494 };
495 
496 /* expose macros as functions for ease of debugging
497 and to expose them to foreign languages without C preprocessor. */
498 #ifdef ageqedge
499 #undef ageqedge
500 #endif
502 {
503  return AGEQEDGE(e, f);
504 }
505 
506 #ifdef agmkout
507 #undef agmkout
508 #endif
510 {
511  return AGMKOUT(e);
512 }
513 
514 #ifdef agmkin
515 #undef agmkin
516 #endif
518 {
519  return AGMKIN(e);
520 }
521 
522 #ifdef agtail
523 #undef agtail
524 #endif
526 {
527  return AGTAIL(e);
528 }
529 
530 #ifdef aghead
531 #undef aghead
532 #endif
534 {
535  return AGHEAD(e);
536 }
537 
538 #ifdef agopp
539 #undef agopp
540 #endif
542 {
543  return AGOPP(e);
544 }
545 
546 #ifdef NOTDEF
547  /* could be useful if we write relabel_edge */
548 static Agedge_t *agfindedge_by_name(Agraph_t * g, Agnode_t * t,
549  Agnode_t * h, char *name)
550 {
551  uint64_t id;
552 
553  if (agmapnametoid(agraphof(t), AGEDGE, name, &id, FALSE))
554  return agfindedge_by_id(g, t, h, id);
555  else
556  return NILedge;
557 }
558 #endif
CGRAPH_API Agedge_t * agopp(Agedge_t *e)
Definition: edge.c:541
CGRAPH_API int agdeledge(Agraph_t *g, Agedge_t *arg_e)
Definition: edge.c:357
#define CGRAPH_API
Definition: cgraph.h:31
unsigned int(* Dthash_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:41
#define AGSEQ(obj)
Definition: cgraph.h:115
#define AGOPP(e)
Definition: cgraph.h:403
void *(* Dtmake_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:38
#define SUCCESS
Definition: cghdr.h:62
Dtdisc_t Ag_mainedge_seq_disc
Definition: edge.c:447
void agrecclose(Agobj_t *obj)
Definition: rec.c:263
Agdesc_t desc
Definition: cgraph.h:241
int agmapnametoid(Agraph_t *g, int objtype, char *str, IDTYPE *result, int allocflag)
Definition: id.c:96
Dtdisc_t Ag_subedge_id_disc
Definition: edge.c:484
CDT_API Dtlink_t * dtextract(Dt_t *)
void agregister(Agraph_t *g, int objtype, void *obj)
Definition: id.c:169
CGRAPH_API Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition: edge.c:56
#define AGID(obj)
Definition: cgraph.h:114
#define dtdelete(d, o)
Definition: cdt.h:264
#define assert(x)
Definition: cghdr.h:47
Agedge_t in
Definition: cgraph.h:147
#define AGIN2OUT(e)
Definition: cgraph.h:401
CGRAPH_API int agisundirected(Agraph_t *g)
Definition: graph.c:187
#define NOTUSED(var)
Definition: cghdr.h:54
Definition: cdt.h:80
#define dtfirst(d)
Definition: cdt.h:254
CGRAPH_API Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition: edge.c:86
Dtlink_t * in_id
Definition: cgraph.h:129
CGRAPH_API Agedge_t * agmkin(Agedge_t *e)
Definition: edge.c:517
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
IDTYPE id
Definition: cgraph.h:96
#define AGOUTEDGE
Definition: cgraph.h:102
uint64_t agnextseq(Agraph_t *g, int objtype)
Definition: graph.c:157
Dtdisc_t Ag_mainedge_id_disc
Definition: edge.c:472
Dtlink_t * out_seq
Definition: cgraph.h:130
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
#define NILstr
Definition: cghdr.h:60
#define AGEQEDGE(e, f)
Definition: cgraph.h:408
CGRAPH_API Agraph_t * agraphof(void *obj)
Definition: obj.c:185
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:525
uint64_t IDTYPE
Definition: cgraph.h:51
CGRAPH_API int ageqedge(Agedge_t *e, Agedge_t *f)
Definition: edge.c:501
CGRAPH_API Agedge_t * agmkout(Agedge_t *e)
Definition: edge.c:509
#define NILnode
Definition: cghdr.h:57
Dict_t * n_id
Definition: cgraph.h:244
void agedgeattr_delete(Agedge_t *e)
Definition: attr.c:418
unsigned has_attrs
Definition: cgraph.h:157
#define NIL(t)
Definition: dthdr.h:13
Agnode_t * node
Definition: cgraph.h:143
CGRAPH_API int agisstrict(Agraph_t *g)
Definition: graph.c:192
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:533
#define AGMKIN(e)
Definition: cgraph.h:405
#define dtsearch(d, o)
Definition: cdt.h:260
unsigned objtype
Definition: cgraph.h:92
#define FAILURE
Definition: cghdr.h:63
Agedge_t out
Definition: cgraph.h:147
#define AGTAG(obj)
Definition: cgraph.h:112
#define AGTAIL(e)
Definition: cgraph.h:406
CGRAPH_API Agraph_t * agparent(Agraph_t *g)
Definition: subg.c:85
#define dtnext(d, o)
Definition: cdt.h:255
void agdeledgeimage(Agraph_t *g, Agedge_t *edge, void *ignored)
Definition: edge.c:327
void agmethod_delete(Agraph_t *g, void *obj)
Definition: obj.c:138
CGRAPH_API Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Definition: edge.c:378
void agfreeid(Agraph_t *g, int objtype, IDTYPE id)
Definition: id.c:131
#define AGMKOUT(e)
Definition: cgraph.h:404
Dtdisc_t Ag_subedge_seq_disc
Definition: edge.c:459
Dtlink_t * out_id
Definition: cgraph.h:129
void agmethod_init(Agraph_t *g, void *obj)
Definition: obj.c:76
CGRAPH_API Agsubnode_t * agsubrep(Agraph_t *g, Agnode_t *n)
Definition: edge.c:157
#define AGOUT2IN(e)
Definition: cgraph.h:402
#define dtinsert(d, o)
Definition: cdt.h:262
int agedgeseqcmpf(Dict_t *d, void *arg_e0, void *arg_e1, Dtdisc_t *disc)
Definition: edge.c:425
char * AgDataRecName
Definition: attr.c:169
unsigned no_loop
Definition: cgraph.h:153
CGRAPH_API Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition: edge.c:95
int agallocid(Agraph_t *g, int objtype, IDTYPE request)
Definition: id.c:126
#define NOT(x)
Definition: cgraph.h:41
Agnode_t * node
Definition: cgraph.h:128
CDT_API int dtrestore(Dt_t *, Dtlink_t *)
#define NILedge
Definition: cghdr.h:58
CGRAPH_API void * agalloc(Agraph_t *g, size_t size)
Definition: mem.c:62
Dtlink_t * in_seq
Definition: cgraph.h:130
Dict_t * e_id
Definition: cgraph.h:245
CGRAPH_API Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition: edge.c:281
void * agdictobjmem(Dict_t *dict, void *p, size_t size, Dtdisc_t *disc)
Definition: utils.c:19
int(* Dtevent_f)(Dt_t *, int, void *, Dtdisc_t *)
Definition: cdt.h:42
CGRAPH_API void * agbindrec(void *obj, char *name, unsigned int size, int move_to_front)
Definition: rec.c:86
void(* Dtfree_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:39
#define AGINEDGE
Definition: cgraph.h:103
CGRAPH_API Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition: edge.c:70
Definition: cdt.h:99
Dict_t * e_seq
Definition: cgraph.h:245
Agraph_t * root
Definition: cgraph.h:135
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:40
#define AGEDGE
Definition: cgraph.h:104
Definition: cgraph.h:91
Agsubnode_t mainsub
Definition: cgraph.h:136
#define AGHEAD(e)
Definition: cgraph.h:407
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
int agedgeidcmpf(Dict_t *d, void *arg_e0, void *arg_e1, Dtdisc_t *disc)
Definition: edge.c:405
CGRAPH_API Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition: node.c:254
void(* agobjfn_t)(Agraph_t *g, Agobj_t *obj, void *arg)
Definition: cgraph.h:210
CGRAPH_API Agedge_t * agidedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, IDTYPE id, int createflag)
Definition: edge.c:259
#define TRUE
Definition: cgraph.h:38