File: cgraph.3

package info (click to toggle)
graphviz 14.0.5-2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 139,388 kB
  • sloc: ansic: 141,938; cpp: 11,957; python: 7,766; makefile: 4,043; yacc: 3,030; xml: 2,972; tcl: 2,495; sh: 1,388; objc: 1,159; java: 560; lex: 423; perl: 243; awk: 156; pascal: 139; php: 58; ruby: 49; cs: 31; sed: 1
file content (640 lines) | stat: -rw-r--r-- 26,102 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
.de P0
.nf
\f5
..
.de P1
\fP
.fi
..
.de Ss
.fl
.ne 2
.SS "\\$1"
..
.TH LIBCGRAPH 3 "28 FEBRUARY 2013"
.SH "NAME"
\fBlibcgraph\fR \- abstract graph library
.SH "SYNOPSIS"
.\"ta .75i 1.5i 2.25i 3i 3.75i 4.5i 5.25i 6i
.PP
.nf
.P0
#include <graphviz/cgraph.h>
.P1
.SS "TYPES"
.P0
Agraph_t;
Agnode_t;
Agedge_t;
Agdesc_t;
Agdisc_t;
Agsym_t;
Agrec_t;
Agcbdisc_t;
.P1
.SS "GLOBALS"
.P0
Agiddisc_t  AgIdDisc;
Agiodisc_t  AgIoDisc;
Agdisc_t    AgDefaultDisc;
.P1
.SS "GRAPHS"
.P0
Agraph_t	*agopen(char *name, Agdesc_t kind, Agdisc_t *disc);
int		agclose(Agraph_t *g);
Agraph_t	*agread(void *channel, Agdisc_t *);
Agraph_t	*agmemread(char *);
Agraph_t	*agconcat(Agraph_t *g, const char *filename, void *channel, Agdisc_t *disc);
int		agwrite(Agraph_t *g, void *channel);
int		agnnodes(Agraph_t *g),agnedges(Agraph_t *g), agnsubg(Agraph_t * g);
int		agisdirected(Agraph_t * g),agisundirected(Agraph_t * g),agisstrict(Agraph_t * g), agissimple(Agraph_t * g); 
bool graphviz_acyclic(Agraph_t *g, const graphviz_acyclic_options_t *opts, size_t *num_rev);
void graphviz_tred(Agraph_t *g, const graphviz_tred_options_t *opts);
void graphviz_unflatten(Agraph_t *g, const graphviz_unflatten_options_t *opts);
.SS "SUBGRAPHS"
.P0
Agraph_t	*agsubg(Agraph_t *g, char *name, int createflag);
Agraph_t	*agidsubg(Agraph_t * g, unsigned long id, int cflag);
Agraph_t	*agfstsubg(Agraph_t *g), agnxtsubg(Agraph_t *);
Agraph_t	*agparent(Agraph_t *g);
int		agdelsubg(Agraph_t * g, Agraph_t * sub);    /* same as agclose() */
.P1
.SS "NODES"
.P0
Agnode_t	*agnode(Agraph_t *g, char *name, int createflag);
Agnode_t	*agidnode(Agraph_t *g, ulong id, int createflag);
Agnode_t	*agsubnode(Agraph_t *g, Agnode_t *n, int createflag);
Agnode_t	*agfstnode(Agraph_t *g);
Agnode_t	*agnxtnode(Agraph_t *g, Agnode_t *n);
Agnode_t	*agprvnode(Agraph_t *g, Agnode_t *n);
Agnode_t	*aglstnode(Agraph_t *g);
int		agdelnode(Agraph_t *g, Agnode_t *n);
int		agdegree(Agraph_t *g, Agnode_t *n, int use_inedges, int use_outedges);
int		agcountuniqedges(Agraph_t * g, Agnode_t * n, int in, int out);
.P1
.SS "EDGES"
.P0
Agedge_t	*agedge(Agraph_t* g, Agnode_t *t, Agnode_t *h, char *name, int createflag);
Agedge_t	*agidedge(Agraph_t * g, Agnode_t * t, Agnode_t * h, unsigned long id, int createflag);
Agedge_t	*agsubedge(Agraph_t *g, Agedge_t *e, int createflag);
Agnode_t	*aghead(Agedge_t *e), *agtail(Agedge_t *e);
Agedge_t	*agfstedge(Agraph_t* g, Agnode_t *n);
Agedge_t	*agnxtedge(Agraph_t* g, Agedge_t *e, Agnode_t *n);
Agedge_t	*agfstin(Agraph_t* g, Agnode_t *n);
Agedge_t	*agnxtin(Agraph_t* g, Agedge_t *e);
Agedge_t	*agfstout(Agraph_t* g, Agnode_t *n);
Agedge_t	*agnxtout(Agraph_t* g, Agedge_t *e);
int		agdeledge(Agraph_t *g, Agedge_t *e);
Agedge_t	*agopp(Agedge_t *e);
int		ageqedge(Agedge_t *e0, Agedge_t *e1);
.SS "STRING ATTRIBUTES"
.P0
Agsym_t	*agattr_text(Agraph_t *g, int kind, char *name, const char *value);
Agsym_t	*agattrsym(void *obj, char *name);
Agsym_t	*agnxtattr(Agraph_t *g, int kind, Agsym_t *attr);
char		*agget(void *obj, char *name);
char		*agxget(void *obj, Agsym_t *sym);
int		agset(void *obj, char *name, char *value);
int		agxset(void *obj, Agsym_t *sym, char *value);
int		agsafeset(void *obj, char *name, char *value, char *def);
int		agcopyattr(void *, void *);
.P1
.SS "RECORDS"
.P0
void		*agbindrec(void *obj, char *name, unsigned int size, move_to_front);
Agrec_t		*aggetrec(void *obj, char *name, int move_to_front);
int		agdelrec(Agraph_t *g, void *obj, char *name);
void		aginit(Agraph_t * g, int kind, char *rec_name, int rec_size, int move_to_front);
void		agclean(Agraph_t * g, int kind, char *rec_name);
.P1
.SS "CALLBACKS"
.P0
int			*agpopdisc(Agraph_t *g);
void		agpushdisc(Agraph_t *g, Agcbdisc_t *disc);
int			agcallbacks(Agraph_t * g, int flag);
.P1
.SS "STRINGS"
.P0
char		*agstrdup(Agraph_t *, char *);
char		*agstrdup_html(Agraph_t *, char *);
int		aghtmlstr(char *);
char		*agstrbind(Agraph_t * g, char *);
int		strfree(Agraph_t *, char *);
char		*agstrcanon(char *, char *);
.P1
.SS "GENERIC OBJECTS"
.P0
Agraph_t	*agraphof(void*);
Agraph_t	*agroot(void*);
int		agcontains(Agraph_t*, void*);
char		*agnameof(void*);
void		agdelete(Agraph_t *g, void *obj);
int		agobjkind(void *obj);
Agrec_t		*AGDATA(void *obj);
ulong		AGID(void *obj);
int		AGTYPE(void *obj);
.P1
.SS "ERROR REPORTING"
.P0
typedef enum { AGWARN, AGERR, AGMAX, AGPREV } agerrlevel_t;
typedef int (*agusererrf) (char*);
agerrlevel_t	agerrno;
agerrlevel_t	agseterr(agerrlevel_t);
char		*aglasterr(void);
int		agerr(agerrlevel_t level, char *fmt, ...);
void		agerrorf(char *fmt, ...);
void		agwarningf(char *fmt, ...);
int		agerrors(void);
agusererrf	agseterrf(agusererrf);
.P1
.SH "DESCRIPTION"
Libcgraph supports graph programming by maintaining graphs in memory
and reading and writing graph files.
Graphs are composed of nodes, edges, and nested subgraphs.
These graph objects may be attributed with string name-value pairs
and programmer-defined records (see Attributes).
.PP
All of Libcgraph's global symbols have the prefix \fBag\fR (case varying).
In the following, if a function has a parameter \fBint createflag\fP and the
object does not exist, the function
will create the specified object if \fBcreateflag\fP is non-zero; otherwise,
it will return NULL.
.SH "GRAPH AND SUBGRAPHS"
.PP
A ``main'' or ``root'' graph defines a namespace for a collection of
graph objects (subgraphs, nodes, edges) and their attributes.
Objects may be named by unique strings or by integer IDs.
.PP
\fBagopen\fP creates a new graph with the given name and kind.
(Graph kinds are \fBAgdirected\fP, \fBAgundirected\fP,
\fBAgstrictdirected\fP, and \fBAgstrictundirected\fP.
A strict graph cannot have multi-edges or self-arcs.)
The final argument points to a discpline structure which can be used
to tailor I/O and ID allocation. Typically, a NULL
value will be used to indicate the default discipline \fBAgDefaultDisc\fP.
\fBagclose\fP deletes a graph, freeing its associated storage.
\fBagread\fP, \fBagwrite\fP, and \fBagconcat\fP perform file I/O 
using the graph file language described below. \fBagread\fP
constructs a new graph while \fBagconcat\fP merges the file
contents with a pre-existing graph.  Though I/O methods may
be overridden, the default is that the channel argument is
a stdio FILE pointer. In that case, if any of the streams are
wide-oriented, the behavior is undefined.
\fBagmemread\fP attempts to read a graph from the input string.
.PP
The functions \fBagisdirected\fP, \fBagisundirected\fP, \fBagisstrict\fP, and \fBagissimple\fP
can be used to query if a graph is directed, undirected, strict (at most one edge with a given tail
and head), or simple (strict with no loops), respectively,
.PP
\fBagsubg\fP finds or creates
a subgraph by name.
\fBagidsubg\fP allows a programmer to specify the subgraph
by a unique integer ID.
A new subgraph is initially empty and
is of the same kind as its parent.  Nested subgraph trees may be created. 
A subgraph's name is only interpreted relative to its parent.
A program can scan subgraphs under a given graph
using \fBagfstsubg\fP and \fBagnxtsubg\fP.  A subgraph is
deleted with \fBagdelsubg\fP (or \fBagclose\fP).
The \fBagparent\fP function returns the immediate parent graph of a subgraph, or itself if the
graph is already a root graph.
.PP
By default, nodes are stored in ordered sets for efficient random
access to insert, find, and delete nodes.
The edges of a node are also stored in ordered sets.
The sets are maintained internally as splay tree dictionaries
using Phong Vo's cdt library.
.PP
\fBagnnodes\fP, \fBagnedges\fP, and \fBagnsubg\fP return the
sizes of node, edge and subgraph sets of a graph.  
The function \fBagdegree\fP returns
the size of the edge set of a nodes, and takes flags
to select in-edges, out-edges, or both.
The function \fBagcountuniqedges\fP returns
the size of the edge set of a nodes, and takes flags
to select in-edges, out-edges, or both. Unlike \fBagdegree\fP, each loop is only
counted once.
.SH "NODES"
A node is created by giving a unique string name or
programmer defined integer ID, and is represented by a
unique internal object. (Node equality can checked
by pointer comparison.)
.PP
\fBagnode\fP searches in a graph or subgraph for a node
with the given name, and returns it if found.
\fBagidnode\fP allows a programmer to specify the node
by a unique integer ID.
\fBagsubnode\fP performs a similar operation on
an existing node and a subgraph.
.PP
\fBagfstnode\fP and \fBagnxtnode\fP scan node lists.
\fBagprvnode\fP and \fPaglstnode\fP are symmetric but scan backward.
The default sequence is order of creation (object timestamp.)
\fBagdelnode\fP removes a node from a graph or subgraph.
.SH "EDGES"
.PP
An abstract edge has two endpoint nodes called tail and head
where all outedges of the same node have it as the tail
value and similarly all inedges have it as the head.
In an undirected graph, head and tail are interchangeable.
If a graph has multi-edges between the same pair of nodes,
the edge's string name behaves as a secondary key.
.PP
\fBagedge\fP searches in a graph or subgraph for an
edge between the given endpoints (with an optional
multi-edge selector name) and returns it if found or created.
Note that, in undirected graphs, a search tries both orderings of 
the tail and head nodes.
If the \fBname\fP 
is NULL, then an anonymous internal
value is generated. \fBagidedge\fP allows a programmer
to create an edge by giving its unique integer ID.
\fBagsubedge\fP performs a similar operation on
an existing edge and a subgraph.
\fBagfstin\fP, \fBagnxtin\fP, \fBagfstout\fP, and 
\fBagnxtout\fP visit directed in- and out- edge lists,
and ordinarily apply only in directed graphs.
\fBagfstedge\fP and \fBagnxtedge\fP visit all edges
incident to a node.  \fBagtail\fP and \fBaghead\fP
get the endpoint of an edge.
\fBagdeledge\fP removes an edge from a graph or subgraph.
.PP
Note that an abstract edge has two distinct concrete representations:
as an in-edge and as an out-edge. In particular, the pointer as an out-edge
is different from the pointer as an in-edge. The function \fBageqedge\fP 
canonicalizes the pointers before doing a comparison and so can be used to
test edge equality. The sense of an edge can be flipped using \fBagopp\fP.
.SH "INTERNAL ATTRIBUTES"
Programmer-defined values may be dynamically
attached to graphs, subgraphs, nodes, and edges.
Such values are either character string data (for I/O)
or uninterpreted binary records
(for implementing algorithms efficiently). 
.SH "STRING ATTRIBUTES"
String attributes are handled automatically in reading
and writing graph files. 
A string attribute is identified by name and by
an internal symbol table entry (\fBAgsym_t\fP) created by Libcgraph.
Attributes of nodes, edges, and graphs (with their subgraphs)
have separate namespaces.  The contents of an \fBAgsym_t\fP
have a \fBchar* name\fP for the attribute's name, a \fBchar* defval\fP
field for the attribute's default value, and an \fBint id\fP field containing
the index of the attribute's specific value for an object in the object's array
of attribute values. 
.PP
\fBagattr\fP creates or looks up attributes.
\fBkind\fP may be \fBAGRAPH\fP, \fBAGNODE\fP, or \fBAGEDGE\fP.
If \fBvalue\fP is \fB(char*)0)\fP, the request is to search
for an existing attribute of the given kind and name.
Otherwise, if the attribute already exists, its default
for creating new objects is set to the given value;
if it does not exist, a new attribute is created with the
given default, and the default is applied to all pre-existing
objects of the given kind. If \fBg\fP is NULL, the default is
set for all graphs created subsequently.
\fBagattrsym\fP is a helper function
that looks up an attribute for a graph object given as an argument.
\fBagnxtattr\fP permits traversing the list of attributes of
a given type.  If \fBNULL\fP is passed as an argument it gets
the first attribute; otherwise it returns the next one in
succession or returns \fBNULL\fP at the end of the list.
\fBagget\fP and \fPagset\fP allow fetching and updating a
string attribute for an object taking the attribute name as
an argument. 
\fBagxget\fP and \fBagxset\fP do this but with
an attribute symbol table entry as an argument (to avoid
the cost of the string lookup). 
Note that \fPagset\fP will fail unless the attribute is
first defined using \fBagattr\fP. 
\fBagsafeset\fP is a
convenience function that ensures the given attribute is
declared before setting it locally on an object.
.PP
It is sometimes convenient to copy all of the attributes from one
object to another. This can be done using \fBagcopyattr\fP. This
fails and returns non-zero of argument objects are different kinds,
or if all of the attributes of the source object have not been declared
for the target object.
.SH "STRINGS"
Libcgraph performs its own storage management of strings as 
reference-counted strings.
The caller does not need to dynamically allocate storage.
.PP
\fBagstrdup\fP returns a pointer to a reference-counted copy of
the argument string, creating one if necessary. \fBagstrbind\fP
returns a pointer to a reference-counted string if it exists, or NULL if not.
All uses of cgraph strings need to be freed using \fBagstrfree\fP
in order to correctly maintain the reference count.
.PP
The cgraph parser handles HTML-like strings. These should be 
indistinguishable from other strings for most purposes. To create
an HTML-like string, use \fBagstrdup_html\fP. The \fBaghtmlstr\fP
function can be used to query if a string is an ordinary string or
an HTML-like string.
.PP
\fBagstrcanon\fP returns a pointer to a version of the input string
canonicalized for output for later re-parsing. This includes quoting
special characters and keywords. The application passes in a buffer as the
second argument. Note that the buffer may not be used; if the input string is in
canonical form, the function will just return a pointer to it.
The input string must have been created using
\fBagstrdup\fP or \fBagstrdup_html\fP.
.SH "RECORDS"
Uninterpreted records may be attached to graphs, subgraphs, nodes,
and edges for efficient operations on values such as marks, weights,
counts, and pointers needed by algorithms.  Application programmers
define the fields of these records, but they must be declared with
a common header as shown below.
.PP
.P0
typedef struct {
    Agrec_t        header;
    /* programmer-defined fields follow */
} user_data_t;
.P1
.PP
Records are created and managed by Libcgraph. A programmer must
explicitly attach them to the objects in a graph, either to
individual objects one at a time via \fBagbindrec\fP, or to
all the objects of the same class in a graph via \fBaginit\fP.
(Note that for graphs, aginit is applied recursively to the
graph and its subgraphs if rec_size is negative (of the
actual rec_size.))
The \fBname\fP argument of a record distinguishes various types of records,
and is programmer defined (Libcgraph reserves the prefix \fB_ag\fR).
If size is 0, the call to \fBagbindrec\fP is simply a lookup.
The function \fBaggetrec\fP can also be used for lookup.
\fBagdelrec\fP deletes a named record from one object.
\fBagclean\fP does the same for all objects of the same
class in an entire graph. 

Internally, records are maintained in circular linked lists
attached to graph objects.
To allow referencing application-dependent data without function
calls or search, Libcgraph allows setting and locking the list
pointer of a graph, node, or edge on a particular record.
This pointer can be obtained with the macro \fBAGDATA(obj)\fP.
A cast, generally within a macro or inline function,
is usually applied to convert the list pointer to
an appropriate programmer-defined type.

To control the setting of this pointer,
the \fBmove_to_front\fP flag may be \fBTRUE\fP
or \fBFALSE\fP.
If \fBmove_to_front\fP is \fBTRUE\fP, the record will be locked at the
head of the list, so it can be accessed directly by \fBAGDATA(obj)\fP.
The lock can be subsequently released or reset by a call to \fBaggetrec\fP. 

.SH "DISCIPLINES"
(This section is not intended for casual users.)
Programmer-defined disciplines customize certain resources-
ID namespace and I/O - needed by Libcgraph.
A discipline struct (or NULL) is passed at graph creation time.
.PP
.P0
struct Agdisc_s {            /* user's discipline */
    Agiddisc_t            *id;
    Agiodisc_t            *io;
} ;
.P1
.PP
A default discipline is supplied when NULL is given for
any of these fields.

.SH "ID DISCIPLINE"
An ID allocator discipline allows a client to control assignment
of IDs (uninterpreted integer values) to objects, and possibly how
they are mapped to and from strings.

.P0
struct Agiddisc_s {             /* object ID allocator */
    void *(*open) (Agraph_t * g, Agdisc_t*);       /* associated with a graph */
    long (*map) (void *state, int objtype, char *str, unsigned long *id, int createflag);
    long (*alloc) (void *state, int objtype, unsigned long id);
    void (*free) (void *state, int objtype, unsigned long id);
    char *(*print) (void *state, int objtype, unsigned long id);
    void (*close) (void *state);
};
.P1
.PP
\fIopen\fP permits the ID discipline to initialize any data
structures that it maintains per individual graph.
Its return value is then passed as the first argument (void *state) to
all subsequent ID manager calls.
.PP
\fIalloc\fP informs the ID manager that Libcgraph is attempting
to create an object with a specific ID that was given by a client.
The ID manager should return TRUE (nonzero) if the ID can be
allocated, or FALSE (which aborts the operation).
.PP
\fIfree\fP is called to inform the ID manager that the
object labeled with the given ID is about to go out of existence.
.PP
\fImap\fP is called to create or look-up IDs by string name
(if supported by the ID manager).  Returning TRUE (nonzero)
in all cases means that the request succeeded (with a valid
ID stored through \fIresult\fP.  There are four cases:
.RS
.IP \[bu] 2
\fIname != NULL\fP and \fIcreateflag == 1\fP:
This requests mapping a string (e.g. a name in a graph file) into a new ID.
If the ID manager can comply, then it stores the result and returns TRUE.
It is then also responsible for being able to \fIprint\fP the ID again
as a string.  Otherwise the ID manager may return FALSE but it must
implement the following (at least for graph file reading and writing to work):
.IP \[bu]
\fIname == NULL\fP and \fIcreateflag == 1\fP:
The ID manager creates a unique new ID of its own choosing. 
Although it may return FALSE if it does not support anonymous objects,
but this is strongly discouraged (to support "local names" in graph files.)
.IP \[bu]
\fIname != NULL\fP and \fIcreateflag == 0\fP:
This is a namespace probe.  If the name was previously mapped into
an allocated ID by the ID manager, then the manager must return this ID.
Otherwise, the ID manager may either return FALSE, or may store
any unallocated ID into result. (This is convenient, for example,
if names are known to be digit strings that are directly converted into integer values.)
.IP \[bu]
\fIname == NULL\fP and \fIcreateflag == 0\fP: forbidden.
.RE
.PP
\fIprint\fP is allowed to return a pointer to a static buffer;
a caller must copy its value if needed past subsequent calls.
\fINULL\fP should be returned by ID managers that do not map names.
.PP
The \fImap\fP and \fIalloc\fP calls do not pass a pointer to the
newly allocated object.  If a client needs to install object
pointers in a handle table, it can obtain them via 
new object callbacks.
.SH "IO DISCIPLINE"
.PP
The I/O discipline provides an abstraction for the reading and writing of graphs.
.P0
struct Agiodisc_s {
    int        (*fread)(void *chan, char *buf, int bufsize);
    int        (*putstr)(void *chan, char *str);
    int        (*flush)(void *chan);    /* sync */
} ;
.P1
.PP
Normally, the \fBFILE\fP structure and its related functions are used for I/O. At times, though,
an application may need to use a totally different type of character source. The associated
state or stream information is provided by the \fIchan\fP argument to \fBagread\fP or \fBagwrite\fP.
The discipline function \fIfread\fP and \fIputstr\fP provide the corresponding functions for
read and writing.

.SH "CALLBACKS"
.PP
An \fBAgcbdisc_t\fP defines callbacks to be invoked by Libcgraph when
initializing, modifying, or finalizing graph objects.
Disciplines are kept on a stack.  Libcgraph automatically
calls the methods on the stack, top-down.  Callbacks are installed
with \fBagpushdisc\fP, uninstalled with \fBagpopdisc\fP, and 
can be held pending or released via \fBagcallbacks\fP.
.SH "GENERIC OBJECTS"
\fBagroot\fP takes any graph object (graph, subgraph, node, edge) and returns
the root graph in which it lives. \fBagraphof\fP does the same, except it 
is the identity function on graphs and subgraphs. Note that there is no 
function to return the least subgraph containing an object, in part because 
this is not well-defined as nodes and edges may be in incomparable subgraphs.
.PP
\fBagcontains\fP(\fIg\fP,\fIobj\fP) returns non-zero if \fIobj\fP is a member 
of (sub)graph \fIg\fP. \fBagdelete\fP(\fIg\fP,\fIobj\fP) is equivalent 
to \fBagclose\fP, \fBagdelnode\fP, and \fBagdeledge\fP for \fIobj\fP being a 
graph, node or edge, respectively. It returns -1 if \fIobj\fP does not 
belong to \fIg\fP.
.PP
\fBAGDATA\fP, \fBAGID\fP, and \fBAGTYPE\fP are macros returning the specified
fields of the argument object. The first is described in the \fBRECORDS\fP
section above. The second returns the unique integer ID associated with
the object. The last returns \fBAGRAPH\fP, \fBAGNODE\fP, and \fBAGEDGE\fP
depending on the type of the object.
.PP
\fBagnameof\fP returns a string descriptor for the object. It returns the name
of the node or graph, and the key of an edge. 
\fBagobjkind\fP is a synonym for \fBAGTYPE\fP.

.SH "ERROR REPORTING"
The library provides a variety of mechanisms to control the reporting
of errors and warnings. At present, there are basically two types of
messages: warnings and errors. A message is only written if its
type has higher priority than a programmer-controlled minimum, which is
\fBAGWARN\fP by default. The programmer can set this value using
\fBagseterr\fP, which returns the previous value. Calling
\fBagseterr(AGMAX)\fP turns off the writing of messages. 
.PP
The function \fBagerr\fP is the main entry point for reporting an
anomaly. The first argument indicates the type of message. Usually,
the first argument is \fBAGWARN\fP or \fBAGERR\fP to indicate warnings
and errors, respectively. Sometimes additional context information is
only available in functions calling the function where the error is
actually caught. In this case, the calling function can indicate that
it is continuing the current error by using \fBAGPREV\fP as the first
argument. The remaining arguments to \fBagerr\fP are the same as
the arguments to \fBprintf\fP. 
.PP
The functions \fBagwarningf\fP and \fBagerrorf\fP are shorthand for
\fBagerr(AGWARN,...)\fP and \fBagerr(AGERR,...)\fP, respectively.
.PP
Some applications desire to directly control the writing of messages.
Such an application can use the function \fBagseterrf\fP to register
the function that the library should call to actually write the message.
The previous error function is returned. By default, the message is
written to \fBstderr\fP.
.PP
Errors not written are stored in a log file. The last recorded error
can be retrieved by calling \fBaglasterr\fP.
Unless the printing of error messages has been completely disabled by a call
to \fBagseterr(AGMAX)\fP, standard error must not be wide-oriented, even if
a user-provided error printing function is provided.
.PP
The function \fBagerrors\fP returns non-zero if errors have been reported. 
.SH "EXAMPLE PROGRAM"
.P0
#include <cgraph.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>

typedef struct {
  Agrec_t hdr;
  int x;
  int y;
  int z;
} mydata;

int main(int argc, char **argv) {
  Agraph_t *g;
    mydata      *p;

  if ((g = agread(stdin, NULL))) {
    int cnt = 0;
    Agsym_t *attr = NULL;
    while ((attr = agnxtattr(g, AGNODE, attr))) {
      cnt++;
    }
    printf("The graph %s has %d attributes\\n", agnameof(g), cnt);

    // make the graph have a node color attribute, default is blue
    attr = agattr_text(g, AGNODE, "color", "blue");

    // create a new graph of the same kind as g
    Agraph_t *h = agopen("tmp", g->desc, NULL);

    // this is a way of counting all the edges of the graph
    cnt = 0;
    for (Agnode_t *v = agfstnode(g); v != NULL; v = agnxtnode(g, v)) {
      for (Agedge_t *e = agfstout(g, v); e != NULL; e = agnxtout(g, e)) {
        cnt++;
      }
    }

    // attach records to edges
    for (Agnode_t *v = agfstnode(g); v != NULL; v = agnxtnode(g, v)) {
      for (Agedge_t *e = agfstout(g, v); e != NULL; e = agnxtout(g, e)) {
        p = (mydata *)agbindrec(e, "mydata", sizeof(mydata), true);
        p->x = 27; // meaningless data access example
        ((mydata *)(AGDATA(e)))->y = 999; // another example
      }
    }
  }
  return 0;
}

.P1
.SH "EXAMPLE GRAPH FILES"
.P0
digraph G {
    a -> b;
    c [shape=box];
    a -> c [weight=29,label="some text"];
    subgraph anything {
        /* the following affects only x,y,z */
        node [shape=circle];
        a; x; y -> z; y -> z;  /* multiple edges */
    }
}

strict graph H {
    n0 -- n1 -- n2 -- n0;  /* a cycle */
    n0 -- {a b c d};       /* a star */
    n0 -- n3;
    n0 -- n3 [weight=1];   /* same edge because graph is strict */
}
.P1
.SH "SEE ALSO"
.BR cdt (3)
.br

.SH "BUGS"
It is difficult to change endpoints of edges, delete string attributes or
modify edge keys.  The work-around is to create a new object and copy the
contents of an old one (but new object obviously has a different ID,
internal address, and object creation timestamp).

The API lacks convenient functions to substitute programmer-defined ordering of
nodes and edges but in principle this can be supported.

The library is not thread safe.
.SH "AUTHOR"
Stephen North, north@research.att.com, AT&T Research.