1 /*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
23 # define CGRAPH_API __declspec(dllexport)
25 # define CGRAPH_API __declspec(dllimport)
28 # define CGRAPH_API /* nothing */
41 #define NIL(type) ((type)0)
43 #define NILgraph NIL(Agraph_t*)
44 #define NILnode NIL(Agnode_t*)
45 #define NILedge NIL(Agedge_t*)
46 #define NILsym NIL(Agsym_t*)
48 typedef uint64_t IDTYPE;
50 /* forward struct type declarations */
51 typedef struct Agtag_s Agtag_t;
52 typedef struct Agobj_s Agobj_t; /* generic object header */
53 typedef struct Agraph_s Agraph_t; /* graph, subgraph (or hyperedge) */
54 typedef struct Agnode_s Agnode_t; /* node (atom) */
55 typedef struct Agedge_s Agedge_t; /* node pair */
56 typedef struct Agdesc_s Agdesc_t; /* graph descriptor */
57 typedef struct Agmemdisc_s Agmemdisc_t; /* memory allocator */
58 typedef struct Agiddisc_s Agiddisc_t; /* object ID allocator */
59 typedef struct Agiodisc_s Agiodisc_t; /* IO services */
60 typedef struct Agdisc_s Agdisc_t; /* union of client discipline methods */
61 typedef struct Agdstate_s Agdstate_t; /* client state (closures) */
62 typedef struct Agsym_s Agsym_t; /* string attribute descriptors */
63 typedef struct Agattr_s Agattr_t; /* string attribute container */
64 typedef struct Agcbdisc_s Agcbdisc_t; /* client event callbacks */
65 typedef struct Agcbstack_s Agcbstack_t; /* enclosing state for cbdisc */
66 typedef struct Agclos_s Agclos_t; /* common fields for graph/subgs */
67 typedef struct Agrec_s Agrec_t; /* generic runtime record */
68 typedef struct Agdatadict_s Agdatadict_t; /* set of dictionaries per graph */
69 typedef struct Agedgepair_s Agedgepair_t; /* the edge object */
70 typedef struct Agsubnode_s Agsubnode_t;
72 /* Header of a user record. These records are attached by client programs
73 dynamically at runtime. A unique string ID must be given to each record
74 attached to the same object. Cgraph has functions to create, search for,
75 and delete these records. The records are maintained in a circular list,
76 with obj->data pointing somewhere in the list. The search function has
77 an option to lock this pointer on a given record. The application must
78 be written so only one such lock is outstanding at a time. */
83 /* following this would be any programmer-defined data */
86 /* Object tag for graphs, nodes, and edges. While there may be several structs
87 for a given node or edges, there is only one unique ID (per main graph). */
89 unsigned objtype:2; /* see literal tags below */
90 unsigned mtflock:1; /* move-to-front lock, see above */
91 unsigned attrwf:1; /* attrs written (parity, write.c) */
92 unsigned seq:(sizeof(unsigned) * 8 - 4); /* sequence no. */
93 IDTYPE id; /* client ID */
97 #define AGRAPH 0 /* can't exceed 2 bits. see Agtag_t. */
100 #define AGINEDGE 3 /* (1 << 1) indicates an edge tag. */
101 #define AGEDGE AGOUTEDGE /* synonym in object kind args */
103 /* a generic graph/node/edge header */
109 #define AGTAG(obj) (((Agobj_t*)(obj))->tag)
110 #define AGTYPE(obj) (AGTAG(obj).objtype)
111 #define AGID(obj) (AGTAG(obj).id)
112 #define AGSEQ(obj) (AGTAG(obj).seq)
113 #define AGATTRWF(obj) (AGTAG(obj).attrwf)
114 #define AGDATA(obj) (((Agobj_t*)(obj))->data)
116 /* This is the node struct allocated per graph (or subgraph). It resides
117 in the n_dict of the graph. The node set is maintained by libdict, but
118 transparently to libgraph callers. Every node may be given an optional
119 string name at its time of creation, or it is permissible to pass NIL(char*)
122 struct Agsubnode_s { /* the node-per-graph-or-subgraph record */
123 Dtlink_t seq_link; /* must be first */
125 Agnode_t *node; /* the object */
126 Dtlink_t *in_id, *out_id; /* by node/ID for random access */
127 Dtlink_t *in_seq, *out_seq; /* by node/sequence for serial access */
133 Agsubnode_t mainsub; /* embedded for main graph */
138 Dtlink_t id_link; /* main graph only */
140 Agnode_t *node; /* the endpoint node */
143 struct Agedgepair_s {
147 struct Agdesc_s { /* graph descriptor */
148 unsigned directed:1; /* if edges are asymmetric */
149 unsigned strict:1; /* if multi-edges forbidden */
150 unsigned no_loop:1; /* if no loops */
151 unsigned maingraph:1; /* if this is the top level graph */
152 unsigned flatlock:1; /* if sets are flattened into lists in cdt */
153 unsigned no_write:1; /* if a temporary subgraph */
154 unsigned has_attrs:1; /* if string attr tables should be initialized */
155 unsigned has_cmpnd:1; /* if may contain collapsed nodes */
158 /* disciplines for external resources needed by libgraph */
160 struct Agmemdisc_s { /* memory allocator */
161 void *(*open) (Agdisc_t*); /* independent of other resources */
162 void *(*alloc) (void *state, size_t req);
163 void *(*resize) (void *state, void *ptr, size_t old, size_t req);
164 void (*free) (void *state, void *ptr);
165 void (*close) (void *state);
168 struct Agiddisc_s { /* object ID allocator */
169 void *(*open) (Agraph_t * g, Agdisc_t*); /* associated with a graph */
170 long (*map) (void *state, int objtype, char *str, IDTYPE *id,
172 long (*alloc) (void *state, int objtype, IDTYPE id);
173 void (*free) (void *state, int objtype, IDTYPE id);
174 char *(*print) (void *state, int objtype, IDTYPE id);
175 void (*close) (void *state);
176 void (*idregister) (void *state, int objtype, void *obj);
180 int (*afread) (void *chan, char *buf, int bufsize);
181 int (*putstr) (void *chan, const char *str);
182 int (*flush) (void *chan); /* sync */
183 /* error messages? */
186 struct Agdisc_s { /* user's discipline */
192 /* default resource disciplines */
194 CGRAPH_API extern Agmemdisc_t AgMemDisc;
195 CGRAPH_API extern Agiddisc_t AgIdDisc;
196 CGRAPH_API extern Agiodisc_t AgIoDisc;
198 CGRAPH_API extern Agdisc_t AgDefaultDisc;
203 /* IO must be initialized and finalized outside Cgraph,
204 * and channels (FILES) are passed as void* arguments. */
207 typedef void (*agobjfn_t) (Agraph_t * g, Agobj_t * obj, void *arg);
208 typedef void (*agobjupdfn_t) (Agraph_t * g, Agobj_t * obj, void *arg,
219 struct Agcbstack_s { /* object event callbacks */
220 Agcbdisc_t *f; /* methods */
221 void *state; /* closure */
222 Agcbstack_t *prev; /* kept in a stack, unlike other disciplines */
226 Agdisc_t disc; /* resource discipline functions */
227 Agdstate_t state; /* resource closures */
228 Dict_t *strdict; /* shared string dict */
229 uint64_t seq[3]; /* local object sequence number counter */
230 Agcbstack_t *cb; /* user and system callback function stacks */
231 unsigned char callbacks_enabled; /* issue user callbacks or hold them? */
232 Dict_t *lookup_by_name[3];
233 Dict_t *lookup_by_id[3];
240 Dict_t *n_seq; /* the node set in sequence */
241 Dict_t *n_id; /* the node set indexed by ID */
242 Dict_t *e_seq, *e_id; /* holders for edge sets */
243 Dict_t *g_dict; /* subgraphs - descendants */
244 Agraph_t *parent, *root; /* subgraphs - ancestors */
245 Agclos_t *clos; /* shared resources */
248 CGRAPH_API void agpushdisc(Agraph_t * g, Agcbdisc_t * disc, void *state);
249 CGRAPH_API int agpopdisc(Agraph_t * g, Agcbdisc_t * disc);
250 CGRAPH_API int agcallbacks(Agraph_t * g, int flag); /* return prev value */
253 CGRAPH_API Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * disc);
254 CGRAPH_API int agclose(Agraph_t * g);
255 CGRAPH_API Agraph_t *agread(void *chan, Agdisc_t * disc);
256 CGRAPH_API Agraph_t *agmemread(const char *cp);
257 CGRAPH_API Agraph_t *agmemconcat(Agraph_t *g, const char *cp);
258 CGRAPH_API void agreadline(int);
259 CGRAPH_API void agsetfile(char *);
260 CGRAPH_API Agraph_t *agconcat(Agraph_t * g, void *chan, Agdisc_t * disc);
261 CGRAPH_API int agwrite(Agraph_t * g, void *chan);
262 CGRAPH_API int agisdirected(Agraph_t * g);
263 CGRAPH_API int agisundirected(Agraph_t * g);
264 CGRAPH_API int agisstrict(Agraph_t * g);
265 CGRAPH_API int agissimple(Agraph_t * g);
268 CGRAPH_API Agnode_t *agnode(Agraph_t * g, char *name, int createflag);
269 CGRAPH_API Agnode_t *agidnode(Agraph_t * g, IDTYPE id, int createflag);
270 CGRAPH_API Agnode_t *agsubnode(Agraph_t * g, Agnode_t * n, int createflag);
271 CGRAPH_API Agnode_t *agfstnode(Agraph_t * g);
272 CGRAPH_API Agnode_t *agnxtnode(Agraph_t * g, Agnode_t * n);
273 CGRAPH_API Agnode_t *aglstnode(Agraph_t * g);
274 CGRAPH_API Agnode_t *agprvnode(Agraph_t * g, Agnode_t * n);
276 CGRAPH_API Agsubnode_t *agsubrep(Agraph_t * g, Agnode_t * n);
277 CGRAPH_API int agnodebefore(Agnode_t *u, Agnode_t *v); /* we have no shame */
280 CGRAPH_API Agedge_t *agedge(Agraph_t * g, Agnode_t * t, Agnode_t * h,
281 char *name, int createflag);
282 CGRAPH_API Agedge_t *agidedge(Agraph_t * g, Agnode_t * t, Agnode_t * h,
283 IDTYPE id, int createflag);
284 CGRAPH_API Agedge_t *agsubedge(Agraph_t * g, Agedge_t * e, int createflag);
285 CGRAPH_API Agedge_t *agfstin(Agraph_t * g, Agnode_t * n);
286 CGRAPH_API Agedge_t *agnxtin(Agraph_t * g, Agedge_t * e);
287 CGRAPH_API Agedge_t *agfstout(Agraph_t * g, Agnode_t * n);
288 CGRAPH_API Agedge_t *agnxtout(Agraph_t * g, Agedge_t * e);
289 CGRAPH_API Agedge_t *agfstedge(Agraph_t * g, Agnode_t * n);
290 CGRAPH_API Agedge_t *agnxtedge(Agraph_t * g, Agedge_t * e, Agnode_t * n);
293 CGRAPH_API Agraph_t *agraphof(void* obj);
294 CGRAPH_API Agraph_t *agroot(void* obj);
295 CGRAPH_API int agcontains(Agraph_t *, void *);
296 CGRAPH_API char *agnameof(void *);
297 CGRAPH_API int agrelabel(void *obj, char *name); /* scary */
298 CGRAPH_API int agrelabel_node(Agnode_t * n, char *newname);
299 CGRAPH_API int agdelete(Agraph_t * g, void *obj);
300 CGRAPH_API int agdelsubg(Agraph_t * g, Agraph_t * sub); /* could be agclose */
301 CGRAPH_API int agdelnode(Agraph_t * g, Agnode_t * arg_n);
302 CGRAPH_API int agdeledge(Agraph_t * g, Agedge_t * arg_e);
303 CGRAPH_API int agobjkind(void *);
306 CGRAPH_API char *agstrdup(Agraph_t *, char *);
307 CGRAPH_API char *agstrdup_html(Agraph_t *, char *);
308 CGRAPH_API int aghtmlstr(char *);
309 CGRAPH_API char *agstrbind(Agraph_t * g, char *);
310 CGRAPH_API int agstrfree(Agraph_t *, char *);
311 CGRAPH_API char *agcanon(char *, int);
312 CGRAPH_API char *agstrcanon(char *, char *);
313 CGRAPH_API char *agcanonStr(char *str); /* manages its own buf */
315 /* definitions for dynamic string attributes */
316 struct Agattr_s { /* dynamic string attributes */
317 Agrec_t h; /* common data header */
318 Dict_t *dict; /* shared dict to interpret attr field */
319 char **str; /* the attribute string values */
322 struct Agsym_s { /* symbol in one of the above dictionaries */
324 char *name; /* attribute's name */
325 char *defval; /* its default value for initialization */
326 int id; /* its index in attr[] */
327 unsigned char kind; /* referent object type */
328 unsigned char fixed; /* immutable value */
329 unsigned char print; /* always print */
332 struct Agdatadict_s { /* set of dictionaries per graph */
333 Agrec_t h; /* installed in list of graph recs */
339 CGRAPH_API Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value);
340 CGRAPH_API Agsym_t *agattrsym(void *obj, char *name);
341 CGRAPH_API Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr);
342 CGRAPH_API int agcopyattr(void *oldobj, void *newobj);
344 CGRAPH_API void *agbindrec(void *obj, char *name, unsigned int size,
346 CGRAPH_API Agrec_t *aggetrec(void *obj, char *name, int move_to_front);
347 CGRAPH_API int agdelrec(void *obj, char *name);
348 CGRAPH_API void aginit(Agraph_t * g, int kind, char *rec_name, int rec_size,
350 CGRAPH_API void agclean(Agraph_t * g, int kind, char *rec_name);
352 CGRAPH_API char *agget(void *obj, char *name);
353 CGRAPH_API char *agxget(void *obj, Agsym_t * sym);
354 CGRAPH_API int agset(void *obj, char *name, char *value);
355 CGRAPH_API int agxset(void *obj, Agsym_t * sym, char *value);
356 CGRAPH_API int agsafeset(void* obj, char* name, char* value, char* def);
358 /* definitions for subgraphs */
359 CGRAPH_API Agraph_t *agsubg(Agraph_t * g, char *name, int cflag); /* constructor */
360 CGRAPH_API Agraph_t *agidsubg(Agraph_t * g, IDTYPE id, int cflag); /* constructor */
361 CGRAPH_API Agraph_t *agfstsubg(Agraph_t * g);
362 CGRAPH_API Agraph_t *agnxtsubg(Agraph_t * subg);
363 CGRAPH_API Agraph_t *agparent(Agraph_t * g);
365 /* set cardinality */
366 CGRAPH_API int agnnodes(Agraph_t * g);
367 CGRAPH_API int agnedges(Agraph_t * g);
368 CGRAPH_API int agnsubg(Agraph_t * g);
369 CGRAPH_API int agdegree(Agraph_t * g, Agnode_t * n, int in, int out);
370 CGRAPH_API int agcountuniqedges(Agraph_t * g, Agnode_t * n, int in, int out);
373 CGRAPH_API void *agalloc(Agraph_t * g, size_t size);
374 CGRAPH_API void *agrealloc(Agraph_t * g, void *ptr, size_t oldsize,
376 CGRAPH_API void agfree(Agraph_t * g, void *ptr);
378 /* an engineering compromise is a joy forever */
379 CGRAPH_API void aginternalmapclearlocalnames(Agraph_t * g);
381 #define agnew(g,t) ((t*)agalloc(g,sizeof(t)))
382 #define agnnew(g,n,t) ((t*)agalloc(g,(n)*sizeof(t)))
384 /* support for extra API misuse warnings if available */
386 #define PRINTF_LIKE(index, first) __attribute__((format(printf, index, first)))
388 #define PRINTF_LIKE(index, first) /* nothing */
392 typedef enum { AGWARN, AGERR, AGMAX, AGPREV } agerrlevel_t;
393 typedef int (*agusererrf) (char*);
394 CGRAPH_API agerrlevel_t agseterr(agerrlevel_t);
395 CGRAPH_API char *aglasterr(void);
396 CGRAPH_API int agerr(agerrlevel_t level, const char *fmt, ...)
398 CGRAPH_API void agerrorf(const char *fmt, ...) PRINTF_LIKE(1, 2);
399 CGRAPH_API void agwarningf(const char *fmt, ...) PRINTF_LIKE(1, 2);
400 CGRAPH_API int agerrors(void);
401 CGRAPH_API int agreseterrors(void);
402 CGRAPH_API agusererrf agseterrf(agusererrf);
406 /* data access macros */
407 /* this assumes that e[0] is out and e[1] is inedge, see edgepair in edge.c */
408 #define AGIN2OUT(e) ((e)-1)
409 #define AGOUT2IN(e) ((e)+1)
410 #define AGOPP(e) ((AGTYPE(e)==AGINEDGE)?AGIN2OUT(e):AGOUT2IN(e))
411 #define AGMKOUT(e) (AGTYPE(e) == AGOUTEDGE? (e): AGIN2OUT(e))
412 #define AGMKIN(e) (AGTYPE(e) == AGINEDGE? (e): AGOUT2IN(e))
413 #define AGTAIL(e) (AGMKIN(e)->node)
414 #define AGHEAD(e) (AGMKOUT(e)->node)
415 #define AGEQEDGE(e,f) (AGMKOUT(e) == AGMKOUT(f))
416 /* These macros are also exposed as functions, so they can be linked against. */
417 #define agtail(e) AGTAIL(e)
418 #define aghead(e) AGHEAD(e)
419 #define agopp(e) AGOPP(e)
420 #define ageqedge(e,f) AGEQEDGE(e,f)
422 #define TAILPORT_ID "tailport"
423 #define HEADPORT_ID "headport"
425 CGRAPH_API extern Agdesc_t Agdirected;
426 CGRAPH_API extern Agdesc_t Agstrictdirected;
427 CGRAPH_API extern Agdesc_t Agundirected;
428 CGRAPH_API extern Agdesc_t Agstrictundirected;
431 void agflatten(Agraph_t * g, int flag);
432 typedef Agsubnode_t Agnoderef_t;
433 typedef Dtlink_t Agedgeref_t;
435 #define AGHEADPOINTER(g) ((Agnoderef_t*)(g->n_seq->data->hh._head))
436 #define AGRIGHTPOINTER(rep) ((Agnoderef_t*)((rep)->seq_link.right?((void*)((rep)->seq_link.right) - offsetof(Agsubnode_t,seq_link)):0))
437 #define AGLEFTPOINTER(rep) ((Agnoderef_t*)((rep)->seq_link.hl._left?((void*)((rep)->seq_link.hl._left) - offsetof(Agsubnode_t,seq_link)):0))
439 #define FIRSTNREF(g) (agflatten(g,1), AGHEADPOINTER(g))
441 #define NEXTNREF(g,rep) (AGRIGHTPOINTER(rep) == AGHEADPOINTER(g)?0:AGRIGHTPOINTER(rep))
443 #define PREVNREF(g,rep) (((rep)==AGHEADPOINTER(g))?0:(AGLEFTPOINTER(rep)))
445 #define LASTNREF(g) (agflatten(g,1), AGHEADPOINTER(g)?AGLEFTPOINTER(AGHEADPOINTER(g)):0)
446 #define NODEOF(rep) ((rep)->node)
448 #define FIRSTOUTREF(g,sn) (agflatten(g,1), (sn)->out_seq)
449 #define LASTOUTREF(g,sn) (agflatten(g,1), (Agedgeref_t*)dtlast(sn->out_seq))
450 #define FIRSTINREF(g,sn) (agflatten(g,1), (sn)->in_seq)
451 #define NEXTEREF(g,rep) ((rep)->right)
452 #define PREVEREF(g,rep) ((rep)->hl._left)
453 /* this is expedient but a bit slimey because it "knows" that dict entries of both nodes
454 and edges are embedded in main graph objects but allocated separately in subgraphs */
455 #define AGSNMAIN(sn) ((sn)==(&((sn)->node->mainsub)))
456 #define EDGEOF(sn,rep) (AGSNMAIN(sn)?((Agedge_t*)((unsigned char*)(rep) - offsetof(Agedge_t,seq_link))) : ((Dthold_t*)(rep))->obj)