cgraph(3)


NAME

   libcgraph - abstract graph library

SYNOPSIS

   #include <graphviz/cgraph.h>

   TYPES
   Agraph_t;
   Agnode_t;
   Agedge_t;
   Agdesc_t;
   Agdisc_t;
   Agsym_t;
   Agrec_t;
   Agcbdisc_t;

   GLOBALS
   Agmemdisc_t AgMemDisc;
   Agiddisc_t  AgIdDisc;
   Agiodisc_t  AgIoDisc;
   Agdisc_t    AgDefaultDisc;

   GRAPHS
   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 *);
   void      agreadline(int line_no);
   void      agsetfile(char *file_name);
   Agraph_t  *agconcat(Agraph_t *g, 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);

   SUBGRAPHS
   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() */

   NODES
   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);

   EDGES
   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);

   STRING ATTRIBUTES
   Agsym_t   *agattr(Agraph_t *g, int kind, char *name, 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 *);

   RECORDS
   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);

   CALLBACKS
   int            *agpopdisc(Agraph_t *g);
   void      agpushdisc(Agraph_t *g, Agcbdisc_t *disc);
   int            agcallbacks(Agraph_t * g, int flag);

   MEMORY
   void      *agalloc(Agraph_t *g, size_t request);
   void      *agrealloc(Agraph_t *g, void *ptr, size_t oldsize, size_t newsize);
   void      agfree(Agraph_t *g, void *ptr);

   STRINGS
   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      *agcanonStr(char *);
   char      *agstrcanon(char *, char *);
   char      *agcanon(char *, int);

   GENERIC OBJECTS
   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);

   ERROR REPORTING
   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);

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).

   All  of  Libcgraph's  global symbols have the prefix ag (case varying).
   In the following, if a function has a parameter int createflag and  the
   object does not exist, the function will create the specified object if
   createflag is non-zero; otherwise, it will return NULL.

GRAPH AND SUBGRAPHS

   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.

   agopen creates a new graph with the given name and kind.  (Graph  kinds
   are Agdirected, Agundirected, Agstrictdirected, and Agstrictundirected.
   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, memory allocation, and ID allocation. Typically, a NULL value will
   be  used  to  indicate  the  default discipline AgDefaultDisc.  agclose
   deletes a graph, freeing its associated storage.  agread, agwrite,  and
   agconcat  perform  file  I/O  using  the  graph file language described
   below. agread constructs a new graph while  agconcat  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.   agmemread  attempts  to  read a graph from the input string.
   agsetfile and agreadline are  helper  functions  that  simply  set  the
   current file name and input line number for subsequent error reporting.

   The  functions agisdirected, agisundirected, agisstrict, and agissimple
   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,

   agsubg finds  or  creates  a  subgraph  by  name.   agidsubg  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  agfstsubg and agnxtsubg.  A subgraph is deleted
   with  agdelsubg  (or  agclose).   The  agparent  function  returns  the
   immediate parent graph of a subgraph, or itself if the graph is already
   a root graph.

   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.

   agnnodes,  agnedges,  and  agnsubg  return  the sizes of node, edge and
   subgraph sets of a graph.  The function agdegree returns  the  size  of
   the edge set of a nodes, and takes flags to select in-edges, out-edges,
   or both.  The function agcountuniqedges returns the size  of  the  edge
   set of a nodes, and takes flags to select in-edges, out-edges, or both.
   Unlike agdegree, each loop is only counted once.

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.)

   agnode searches in a graph or subgraph for a node with the given  name,
   and  returns  it if found.  agidnode allows a programmer to specify the
   node by a unique integer ID.  agsubnode performs a similar operation on
   an existing node and a subgraph.

   agfstnode  and  agnxtnode scan node lists.  agprvnode and aglstnode are
   symmetric but scan backward.  The default sequence is order of creation
   (object timestamp.)  agdelnode removes a node from a graph or subgraph.

EDGES

   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.

   agedge  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 name  is  NULL,  then  an
   anonymous  internal value is generated. agidedge allows a programmer to
   create an edge by giving its unique integer ID.  agsubedge  performs  a
   similar  operation  on  an  existing  edge  and  a  subgraph.  agfstin,
   agnxtin, agfstout, and agnxtout visit directed in- and out- edge lists,
   and  ordinarily apply only in directed graphs.  agfstedge and agnxtedge
   visit all edges incident to a node.  agtail and aghead get the endpoint
   of an edge.  agdeledge removes an edge from a graph or subgraph.

   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 ageqedge
   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 agopp.

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).

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 (Agsym_t) created by Libcgraph.  Attributes
   of  nodes,  edges,  and  graphs  (with  their  subgraphs) have separate
   namespaces.  The contents of an Agsym_t  have  a  char*  name  for  the
   attribute's  name,  a  char*  defval  field for the attribute's default
   value, and an int id field containing  the  index  of  the  attribute's
   specific value for an object in the object's array of attribute values.

   agattr  creates or looks up attributes.  kind may be AGRAPH, AGNODE, or
   AGEDGE.  If value is  (char*)0),  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 g is NULL, the default is set for all
   graphs created subsequently.  agattrsym is a helper function that looks
   up  an  attribute  for  a graph object given as an argument.  agnxtattr
   permits traversing the list of attributes of a given type.  If NULL  is
   passed as an argument it gets the first attribute; otherwise it returns
   the next one in succession or returns NULL at  the  end  of  the  list.
   agget  and  agset allow fetching and updating a string attribute for an
   object taking the attribute name as an argument.  agxget and agxset  do
   this  but with an attribute symbol table entry as an argument (to avoid
   the cost of the string lookup).  Note that agset will fail  unless  the
   attribute  is  first  defined using agattr.  agsafeset is a convenience
   function that ensures the given attribute is declared before setting it
   locally on an object.

   It  is  sometimes  convenient  to  copy  all of the attributes from one
   object to another. This can be done using agcopyattr.  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.

STRINGS

   Libcgraph  performs its own storage management of strings as reference-
   counted strings.  The caller does  not  need  to  dynamically  allocate
   storage.

   agstrdup  returns a pointer to a reference-counted copy of the argument
   string, creating one if necessary. agstrbind 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 agstrfree in order  to  correctly
   maintain the reference count.

   The   cgraph   parser   handles  HTML-like  strings.  These  should  be
   indistinguishable from other strings for most purposes.  To  create  an
   HTML-like string, use agstrdup_html. The aghtmlstr function can be used
   to query if a string is an ordinary string or an HTML-like string.

   agcanonStr  returns  a  pointer  to  a  version  of  the  input  string
   canonicalized  for  output  for later re-parsing. This includes quoting
   special characters and keywords. It uses its own  internal  buffer,  so
   the  value  will be lost on the next call to agcanonStr.  agstrcanon is
   an unsafe version of agcanonStr, in which 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.  For both of the functions, the input string must have
   been created using agstrdup or agstrdup_html.  Finally,  agcanonStr  is
   identical  with  agcanonStr  except  it  can be used with any character
   string. The second argument indicates whether or not the string  should
   be canonicalized as an HTML-like string.

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.

   typedef struct {
       Agrec_t        header;
       /* programmer-defined fields follow */
   } user_data_t;

   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 agbindrec, or to all the objects of the same
   class in a graph via aginit.  (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 name argument  of  a  record  distinguishes
   various types of records, and is programmer defined (Libcgraph reserves
   the prefix _ag).  If size is 0, the  call  to  agbindrec  is  simply  a
   lookup.   The  function aggetrec can also be used for lookup.  agdelrec
   deletes a named record from one object.  agclean 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 AGDATA(obj).  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 move_to_front flag may be
   TRUE or FALSE.  If move_to_front is TRUE, the record will be locked  at
   the  head  of  the list, so it can be accessed directly by AGDATA(obj).
   The lock can be subsequently released or reset by a call to aggetrec.

DISCIPLINES

   (This section is not intended for  casual  users.)   Programmer-defined
   disciplines  customize certain resources- ID namespace, memory, and I/O
   - needed by Libcgraph.  A discipline struct  (or  NULL)  is  passed  at
   graph creation time.

   struct Agdisc_s {            /* user's discipline */
       Agmemdisc_t            *mem;
       Agiddisc_t            *id;
       Agiodisc_t            *io;
   } ;

   A  default  discipline  is supplied when NULL is given for any of these
   fields.

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.

   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);
   };

   open 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.

   alloc 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).

   free  is  called  to inform the ID manager that the object labeled with
   the given ID is about to go out of existence.

   map 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  result.   There  are
   four cases:

   name  != NULL and createflag == 1: 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  print  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):

   name == NULL and createflag == 1: 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.)

   name  !=  NULL  and createflag == 0: 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.)

   name == NULL and createflag == 0: forbidden.

   print is allowed to return a pointer to a static buffer; a caller  must
   copy  its  value  if  needed  past  subsequent  calls.   NULL should be
   returned by ID managers that do not map names.

   The map and alloc 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.

IO DISCIPLINE

   The I/O discipline provides an abstraction for the reading and  writing
   of graphs.
   struct Agiodisc_s {
       int        (*fread)(void *chan, char *buf, int bufsize);
       int        (*putstr)(void *chan, char *str);
       int        (*flush)(void *chan);    /* sync */
   } ;
   Normally,  the  FILE  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 chan argument to agread or agwrite.  The
   discipline   function   fread  and  putstr  provide  the  corresponding
   functions for read and writing.

MEMORY DISCIPLINE

   Memory management in Libcgraph is handled on a per  graph  basis  using
   the memory discipline.
   struct Agmemdisc_s {    /* memory allocator */
       void    *(*open)(Agdisc_t*);        /* independent of other resources */
       void    *(*alloc)(void *state, size_t req);
       void    *(*resize)(void *state, void *ptr, size_t old, size_t req);
       void    (*free)(void *state, void *ptr);
       void    (*close)(void *state);
   } ;
   The open function is used to initialize the memory subsystem, returning
   state information that is passed to the calls  to  alloc,  resize,  and
   free.   The  semantics  of these should be comparable to the standard C
   library functions malloc, realloc, and  free,  except  that  new  space
   created  by  agalloc  and  agrealloc  should  be zeroed out.  The close
   function is  used  to  terminate  the  memory  subsystem,  freeing  any
   additional open resources.  For actual allocation, the library uses the
   functions agalloc, agrealloc, and agfree, which provide simple wrappers
   for the underlying discipline functions alloc, resize, and free.

   When  Libcgraph  is  compiled  with Vmalloc (which is not the default),
   each graph has its own heap.   Programmers  may  allocate  application-
   dependent  data  within  the  same  heap as the rest of the graph.  The
   advantage is that a graph can be  deleted  by  atomically  freeing  its
   entire heap without scanning each individual node and edge.

CALLBACKS

   An  Agcbdisc_t  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 agpushdisc,  uninstalled
   with agpopdisc, and can be held pending or released via agcallbacks.

GENERIC OBJECTS

   agroot takes any graph object (graph, subgraph, node, edge) and returns
   the root graph in which it lives. agraphof 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.

   agcontains(g,obj) returns non-zero if obj is a member of (sub)graph  g.
   agdelete(g,obj)  is equivalent to agclose, agdelnode, and agdeledge for
   obj being a graph, node or edge, respectively. It  returns  -1  if  obj
   does not belong to g.

   AGDATA,  AGID,  and AGTYPE are macros returning the specified fields of
   the argument object. The first is  described  in  the  RECORDS  section
   above.  The  second  returns  the unique integer ID associated with the
   object. The last returns AGRAPH, AGNODE, and AGEDGE  depending  on  the
   type of the object.

   agnameof  returns  a  string  descriptor for the object. It returns the
   name of the node or graph, and the key of  an  edge.   agobjkind  is  a
   synonym for AGTYPE.

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
   AGWARN  by  default.  The programmer can set this value using agseterr,
   which returns the previous value. Calling agseterr(AGMAX) turns off the
   writing of messages.

   The  function  agerr  if the main entry point for reporting an anomaly.
   The first argument indicates the type of message.  Usually,  the  first
   argument   in   AGWARN  or  AGERR  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 AGPREV as the first argument. The
   remaining arguments to agerr are the same as the arguments to printf.

   The   functions   agwarningf   and   agerrorf   are    shorthand    for
   agerr(AGERR,...) and agerr(AGWARN,...), respectively.

   Some  applications  desire to directly control the writing of messages.
   Such an application can use the  function  agseterrf  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 stderr.

   Errors  not  written  are stored in a log file. The last recorded error
   can be retreived by calling aglasterr.

   The function agerrors returns non-zero if errors have been reported.

EXAMPLE PROGRAM

   #include <cgraph.h>
   typedef struct {Agrec_t hdr; int x,y,z;} mydata;

   main(int argc, char **argv)
   {
       Agraph_t    *g;
       Agnode_t    *v;
       Agedge_t    *e;
       Agsym_t     *attr;
       Dict_t      *d
       int         cnt;
       mydata      *p;

       if (g = agread(stdin,NIL(Agdisc_t*))) {
           cnt = 0; attr = 0;
           while (attr = agnxtattr(g, AGNODE, attr)) cnt++;
           printf("The graph %s has %d attributes0,agnameof(g),cnt);

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

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

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

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

EXAMPLE GRAPH FILES

   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 */
   }

SEE ALSO

   Libcdt(3)

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.

AUTHOR

   Stephen North, north@research.att.com, AT&T Research.

                           28 FEBRUARY 2013                   LIBCGRAPH(3)





Opportunity


Personal Opportunity - Free software gives you access to billions of dollars of software at no cost. Use this software for your business, personal use or to develop a profitable skill. Access to source code provides access to a level of capabilities/information that companies protect though copyrights. Open source is a core component of the Internet and it is available to you. Leverage the billions of dollars in resources and capabilities to build a career, establish a business or change the world. The potential is endless for those who understand the opportunity.

Business Opportunity - Goldman Sachs, IBM and countless large corporations are leveraging open source to reduce costs, develop products and increase their bottom lines. Learn what these companies know about open source and how open source can give you the advantage.





Free Software


Free Software provides computer programs and capabilities at no cost but more importantly, it provides the freedom to run, edit, contribute to, and share the software. The importance of free software is a matter of access, not price. Software at no cost is a benefit but ownership rights to the software and source code is far more significant.


Free Office Software - The Libre Office suite provides top desktop productivity tools for free. This includes, a word processor, spreadsheet, presentation engine, drawing and flowcharting, database and math applications. Libre Office is available for Linux or Windows.





Free Books


The Free Books Library is a collection of thousands of the most popular public domain books in an online readable format. The collection includes great classical literature and more recent works where the U.S. copyright has expired. These books are yours to read and use without restrictions.


Source Code - Want to change a program or know how it works? Open Source provides the source code for its programs so that anyone can use, modify or learn how to write those programs themselves. Visit the GNU source code repositories to download the source.





Education


Study at Harvard, Stanford or MIT - Open edX provides free online courses from Harvard, MIT, Columbia, UC Berkeley and other top Universities. Hundreds of courses for almost all major subjects and course levels. Open edx also offers some paid courses and selected certifications.


Linux Manual Pages - A man or manual page is a form of software documentation found on Linux/Unix operating systems. Topics covered include computer programs (including library and system calls), formal standards and conventions, and even abstract concepts.