This was previously deprecated in favor of lib/cgraph. Closes #1549.
+++ /dev/null
-# $Id$ $Revision$
-## Process this file with automake to produce Makefile.in
-
-AGRAPH_VERSION="4:0:0"
-
-pdfdir = $(pkgdatadir)/doc/pdf
-pkgconfigdir = $(libdir)/pkgconfig
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/lib/cdt
-
-pkginclude_HEADERS = agraph.h
-noinst_HEADERS = aghdr.h malloc.h grammar.h
-noinst_LTLIBRARIES = libagraph_C.la
-lib_LTLIBRARIES = libagraph.la
-pkgconfig_DATA = libagraph.pc
-man_MANS = agraph.3
-pdf_DATA = agraph.3.pdf
-
-libagraph_C_la_SOURCES = agerror.c apply.c attr.c \
- edge.c flatten.c grammar.y graph.c id.c imap.c io.c \
- mem.c node.c obj.c pend.c rec.c refstr.c scan.l subg.c \
- utils.c write.c
-
-libagraph_la_LDFLAGS = -version-info $(AGRAPH_VERSION) -no-undefined
-libagraph_la_SOURCES = $(libagraph_C_la_SOURCES)
-libagraph_la_LIBADD = $(top_builddir)/lib/cdt/libcdt.la
-
-scan.o scan.lo: scan.c grammar.h
-
-scan.c: $(top_srcdir)/lib/agraph/scan.l
- @LEX@ -i $(top_srcdir)/lib/agraph/scan.l
- @SED@ "s/yy/aag/g" < @LEX_OUTPUT_ROOT@.c > scan.c
- rm @LEX_OUTPUT_ROOT@.c
-
-grammar.c: y.tab.c
- @SED@ "s/yy/aag/g" < y.tab.c > grammar.c
-
-grammar.h: y.tab.h
- @SED@ "s/yy/aag/g" < y.tab.h > grammar.h
-
-y.tab.c y.tab.h: y.output
-
-y.output: $(top_srcdir)/lib/agraph/grammar.y
- @YACC@ -dv $(top_srcdir)/lib/agraph/grammar.y
-
-agraph.3.pdf: agraph.3.ps
- @PS2PDF@ $< $@
-
-agraph.3.ps: $(srcdir)/agraph.3
- @GROFF@ -Tps -man $< >$@
-
-EXTRA_DIST = $(man_MANS) $(pdf_DATA) cmpnd.c dotdge.c \
- main.c tester.c README grammar.c grammar.h scan.c \
- y.tab.c y.tab.h y.output
-
-DISTCLEANFILES = $(pdf_DATA) grammar.[ch] scan.c y.output y.tab.[ch] agraph.3.ps
+++ /dev/null
-From /home/north/src/graph/dynagraph/graph
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include <stdio.h>
-#include "aghdr.h"
-
-static char *Message[] = {
- "", /* 0 is not assigned */
- "%s", /* AGERROR_SYNTAX == 1 */
- "out of memory", /* AGERROR_MEMORY == 2 */
- "unimplemented feature: %s", /* AGERROR_UNIMPL == 3 */
- "move_to_front lock %s", /* AGERROR_MTFLOCK== 4 */
- "compound graph error %s", /* AGERROR_CMPND == 5 */
- "bad object pointer %s", /* AGERROR_BADOBJ == 6 */
- "object ID overflow", /* AGERROR_IDOVFL == 7 */
- "flat lock violation", /* AGERROR_MTFLOCK== 8 */
- "object and graph disagree" /* AGERROR_WRONGGRAPH==9 */
-};
-
-/* default error handler */
-void agerror(int code, char *str)
-{
- /* fprintf(stderr,"libgraph runtime error: "); */
- fprintf(stderr, Message[code], str);
- fprintf(stderr, "\n");
-
- if (code != AGERROR_SYNTAX)
- exit(1);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#ifndef ATT_GRAPHPVT_H
-#define ATT_GRAPHPVT_H 1
-#define _BLD_agraph 1
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "agraph.h"
-
-#ifdef HAVE_AST
-# include <ast.h>
-# include <vmalloc.h>
-#else
-# ifdef HAVE_VMALLOC
-# include <vmalloc.h>
-# endif /* HAVE_VMALLOC */
-# include <sys/types.h>
-# include <stdlib.h>
-# ifdef HAVE_STRINGS_H
-# include <strings.h>
-# endif /* HAVE_STRINGS_H */
-# ifdef HAVE_STRING_H
-# include <string.h>
-# endif /* HAVE_STRING_H */
-# ifdef HAVE_UNISTD_H
-# include <unistd.h>
-# endif /* HAVE_UNISTD_H */
-# ifdef HAVE_STDINT_H
-# include <stdint.h>
-# endif
-# ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-# endif
-#endif /* HAVE_AST */
-
-#ifdef DEBUG
-# include <assert.h>
-#else
-# define assert(x)
-#endif
-
-#ifndef streq
-#define streq(s,t) ((*s == *t) && !strcmp((s),(t)))
-#endif
-#ifdef offsetof
-#undef offsetof
-#endif
-#ifdef HAVE_INTPTR_T
-#define offsetof(typ,fld) ((intptr_t)(&(((typ*)0)->fld)))
-#else
-#define offsetof(typ,fld) ((int)(&(((typ*)0)->fld)))
-#endif
-#define NOTUSED(var) (void) var
-
-#define NILgraph NIL(Agraph_t*)
-#define NILnode NIL(Agnode_t*)
-#define NILedge NIL(Agedge_t*)
-#define NILsym NIL(Agsym_t*)
-#define NILstr NIL(char*)
-
-#define MAX_OUTPUTLINE 80
-#define SUCCESS 0
-#define FAILURE -1
-#define LOCALNAMEPREFIX '%'
-
-#define AGDISC(g,d) ((g)->clos->disc.d)
-#define AGCLOS(g,d) ((g)->clos->state.d)
-#define AGNEW(g,t) ((t*)(agalloc(g,sizeof(t))))
-
-#define TAIL_ID "tailport"
-#define HEAD_ID "headport"
-
-#define ISALNUM(c) ((isalnum(c)) || ((c) == '_') || (!isascii(c)))
-
- /* functional definitions */
- typedef Agobj_t *(*agobjsearchfn_t) (Agraph_t * g, Agobj_t * obj);
- int agapply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
- int preorder);
-
- /* global variables */
- EXTERN Agraph_t *Ag_G_global;
- extern char *AgDataRecName;
-
- /* set ordering disciplines */
- extern Dtdisc_t Ag_obj_id_disc;
- extern Dtdisc_t Ag_obj_seq_disc;
- extern Dtdisc_t Ag_edge_disc;
- extern Agcbdisc_t AgAttrdisc;
-
- /* flattening */
- void agnotflat(Agraph_t * g);
- void agflatten_edges(Agraph_t * g, Agnode_t * n);
-
- /* internal constructor of graphs and subgraphs */
- Agraph_t *agopen1(Agraph_t * g);
- void agstrclose(Agraph_t * g);
-
- /* object set management */
- Agnode_t *agfindnode_by_id(Agraph_t * g, unsigned long id);
- Dtcompar_f agdictorder(Agraph_t *, Dict_t *, Dtcompar_f);
- int agobjidcmpf(Dict_t * d, void *, void *, Dtdisc_t * disc);
- int agnamecmpf(Dict_t * d, void *, void *, Dtdisc_t * disc);
- void agset_node_disc(Agraph_t * g, Dtdisc_t * disc);
- unsigned long agnextseq(Agraph_t * g, int objtype);
-
-/* dict helper functions */
- Dict_t *agdtopen(Agraph_t * g, Dtdisc_t * disc, Dtmethod_t * method);
- void agdtdisc(Agraph_t * g, Dict_t * dict, Dtdisc_t * disc);
- long agdtdelete(Agraph_t * g, Dict_t * dict, void *obj);
- void agdtclose(Agraph_t * g, Dict_t * dict);
- void *agdictobjmem(Dict_t * dict, Void_t * p, size_t size,
- Dtdisc_t * disc);
- void agdictobjfree(Dict_t * dict, Void_t * p, Dtdisc_t * disc);
- void *agrealbindrec(void *obj, char *name, unsigned int size, int mtf,
- int norecur);
-
- /* name-value pair operations */
- Agdatadict_t *agdatadict(Agraph_t * g);
- Agattr_t *agattrrec(void *obj);
-
- void agraphattr_init(Agraph_t * g, int norecur);
- void agraphattr_delete(Agraph_t * g);
- void agnodeattr_init(Agnode_t * n, int norecur);
- void agnodeattr_delete(Agnode_t * n);
- void agedgeattr_init(Agedge_t * e, int norecur);
- void agedgeattr_delete(Agedge_t * e);
-
- /* parsing and lexing graph files */
- void aglexinit(Agdisc_t * disc, void *ifile);
- int aaglex(void);
- void aglexeof(void);
- void aagerror(char *);
- int aagparse(void);
-
- /* ID management */
- int agmapnametoid(Agraph_t * g, int objtype, char *str,
- unsigned long *result, int allocflag);
- int agallocid(Agraph_t * g, int objtype, unsigned long request);
- void agfreeid(Agraph_t * g, int objtype, unsigned long id);
- char *agprintid(Agobj_t * obj);
- int aginternalmaplookup(Agraph_t * g, int objtype, char *str,
- unsigned long *result);
- void aginternalmapinsert(Agraph_t * g, int objtype, char *str,
- unsigned long result);
- char *aginternalmapprint(Agraph_t * g, int objtype, unsigned long id);
- int aginternalmapdelete(Agraph_t * g, int objtype, unsigned long id);
- void aginternalmapclose(Agraph_t * g);
-
- /* internal set operations */
- void agedgesetop(Agraph_t * g, Agedge_t * e, int insertion);
- void agdelnodeimage(Agnode_t * node, void *ignored);
-
- long agdelsubg(Agraph_t * g, Agraph_t * sub);
- int agdelnode(Agnode_t * arg_n);
- int agdeledge(Agedge_t * arg_e);
- int agrename(Agobj_t * obj, char *newname);
- void agrecclose(Agobj_t * obj);
-
- void agmethod_init(Agraph_t * g, void *obj);
- void agmethod_upd(Agraph_t * g, void *obj, Agsym_t * sym);
- void agmethod_delete(Agraph_t * g, void *obj);
-
-#define CB_INITIALIZE 100
-#define CB_UPDATE 101
-#define CB_DELETION 102
- void agsyspushdisc(Agraph_t * g, Agcbdisc_t * cb, void *state,
- int stack);
- int agsyspopdisc(Agraph_t * g, Agcbdisc_t * cb, int stack);
- void agrecord_callback(Agobj_t * obj, int kind, Agsym_t * optsym);
- void aginitcb(void *obj, Agcbstack_t * disc);
- void agupdcb(void *obj, Agsym_t * sym, Agcbstack_t * disc);
- void agdelcb(void *obj, Agcbstack_t * disc);
-
-#endif /* ATT_GRAPHPVT_H */
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-.de P0
-.nf
-\f5
-..
-.de P1
-\fP
-.fi
-..
-.de Ss
-.fl
-.ne 2
-.SS "\\$1"
-..
-.TH LIBAGRAPH 3 "8 MARCH 1996"
-.SH "NAME"
-\fBAgraph\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/agraph.h>
-.P1
-.Ss "TYPES"
-.P0
-Agraph_t;
-Agnode_t;
-Agedge_t;
-Agdesc_t;
-Agdisc_t;
-Agsym_t;
-.P1
-.Ss "GRAPHS"
-.P0
-Agraph_t *agopen(char *name, Agdesc_t kind, Agdisc_t *disc);
-int agclose(Agraph_t *g);
-Agraph_t *agread(void *file, Agdisc_t *);
-Agraph_t *agconcat(Agraph_t *g, void *chan, Agdisc_t *disc)
-int agwrite(Agraph_t *g, void *file);
-int agnnodes(Agraph_t *g),agnedges(Agraph_t *g);
-.Ss "SUBGRAPHS"
-.P0
-Agraph_t *agsubg(Agraph_t *g, char *name, int createflag);
-Agraph_t *agfstsubg(Agraph_t *g), agnxtsubg(Agraph_t *);
-Agraph_t *agparent(Agraph_t *g),*agroot(Agraph_t *g);
-.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(Agnode_t *n);
-int agdelnode(Agraph_t *g, Agnode_t *n);
-int agrename(Agraph_t *g, Agnode_t *n, char *newname);
-int agdegree(Agnode_t *n, int use_inedges, int use_outedges);
-.P1
-.Ss "EDGES"
-.P0
-Agedge_t *agedge(Agnode_t *t, Agnode_t *h, char *name, int createflag);
-Agedge_t *agsubedge(Agraph_t *g, Agedge_t *e, int createflag);
-int agdeledge(Agraph_t *g, Agedge_t *e);
-
-Agnode_t *aghead(Agedge_t *e), *agtail(Agedge_t *e);
-Agedge_t *agfstedge(Agnode_t *n);
-Agedge_t *agnxtedge(Agedge_t *e, Agnode_t *n);
-Agedge_t *agfstin(Agnode_t *n);
-Agedge_t *agnxtin(Agedge_t *e);
-Agedge_t *agfstout(Agnode_t *n);
-Agedge_t *agnxtout(Agedge_t *e);
-.Ss "FLATTENED LISTS"
-.P0
-int agflatten(Agraph_t *graph, int flag);
-Agnode_t *agfstn(Agraph_t *g), *agnxtn(Agnode_t *n);
-Agedge_t *agfout(Agnode_t *n), *agfin(Agnode_t *n), *agnxte(Agedge_t *e);
-.P1
-.Ss "STRING ATTRIBUTES"
-.P0
-Agsym_t *agattr(Agraph_t *g, int kind, char *name, char *value);
-Agsym_t *agattrnxt(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);
-.P1
-.Ss "RECORDS"
-.P0
-void *agnewrec(Agraph_t *g, void *obj, char *name, unsigned int size);
-Agrec_t *aggetrec(void *obj, char *name, int move_to_front);
-int agdelrec(Agraph_t *g, void *obj, char *name);
-.P1
-.Ss "CALLBACKS"
-.P0
-Agcbdisc_t *agpopdisc(Agraph_t *g);
-void agpushdisc(Agraph_t *g, Agcbdisc_t *disc);
-void agmethod(Agraph_t *g, void *obj, Agcbdisc_t *disc, int initflag);
-.P1
-.Ss "MEMORY"
-.P0
-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);
-.P1
-.Ss "GENERIC OBJECTS"
-.P0
-Agraph_t *agraphof(void*);
-char *agnameof(void*);
-int agisarootobj(void*);
-Agrec_t *AGDATA(void *obj);
-ulong AGID(void *obj);
-int AGTYPE(void *obj);
-.P1
-.SH "DESCRIPTION"
-Libagraph supports graph programming by maintaining graphs in memory
-and reading and writing graph files. Graphs, nodes and edges
-may be attributed with programmer-defined records and string
-name-value pairs.
-Graphs are composed of nodes, edges, and nested subgraphs.
-Internally, Libagraph depends extensively on Libcdt (formerly
-Libdict) for set representation.
-.PP
-All of Libagraph's global symbols have the prefix \fBag\fR (case varying).
-.SH "GRAPHS"
-.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 32-bit IDs.
-By default \fBdata\fP points to runtime records containing
-application-dependent data, keyed by name (see Attributes).
-\fBdesc\fP records if a graph is directed or undirected, and if it is strict
-or allows multi-edges and self-arcs.
-.PP
-\fBagopen\fP creates a new graph with the given name and graph kind
-descriptor (global values are \fBAgdirected\fP, \fBAgundirected\fP,
-\fBAgstrictdirected\fP, and \fBAgstrictundirected\fP).
-\fBagclose\fP deletes a graph, freeing all its associated
-storage. \fBagread\fP and \fBagwrite\fP perform file I/O
-(see Graph File Language bellow). \fBagsubg\fP creates a new subgraph,
-which always inherits the graph kind of its parent. The new subgraph is
-initially empty. Nested subgraph trees may be created. The name of
-a subgraph is interpreted only relative to the given parent graph.
-\fBagsubglist\fP returns a list (possibly empty) of subgraphs of
-a given graph.
-.PP
-By default, nodes are kept in ordered sets in \fBn_dict\fP,
-allowing efficient random access to insert, find, and delete nodes.
-Similarly the edges of each node are kept in ordered sets.
-The sets are maintained as splay tree dictionaries.
-\fBagflatten\fP allows flattening trees into linked lists,
-which may thereafter be traversed very quickly without function
-calls for low overhead in critical sections of code.
-In this mode, sets are locked to prevent updates or random access searches,
-though it is still legal to call Libagraph to scan lists sequentially.
-The flag argument requests flattening and locking (if boolean true),
-or unlocking (if false).
-In-line functions or macros for list traversal are given below
-under Nodes and Edges. Note that flattening a graph does not
-automatically flatten its subgraphs.
-.PP
-\fBagnnodes\fP, \fBagnedges\fP, and \fBagdegree\fP return the
-cardinalities of node and edge sets. The latter takes flags
-to select in-edges, out-edges, or both.
-.PP
-\fBAgdisc_t\fP specifies callbacks invoked when initializing,
-modifying, or finalizinf graph objects. (Casual users can ignore
-the following.) Disciplines are kept on a stack. Libagraph automatically
-calls the methods on the stack, top-down. A method can obtain its
-data (closure) via \f5aggetuserptr\fP.
-.PP
-When Libagraph is compiled with Vmalloc, 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.
-.SH "NODES"
-A node is identified uniquely by name and graph pointer.
-Node pointers are not unique\(em separate node structs are created
-per subgraph. Name pointers are unique, though, because each
-graph has its own shared string pool.
-.PP
-\fBagnode\fP searches in a graph or subgraph for a node
-with the given name, and returns it if found.
-If not found, if \fBcreateflag\fP is boolean true
-a new node is created and returned, otherwise a nil
-pointer is returned.
-\fBagsubnode\fP takes an existing node as a template,
-usually to find or insert a node in a subgraph.
-
-The default ordering of nodes is by order of creation (sequence).
-Internally, Libagraph switches between ID searching and sequence
-ordering as necessary. \fBagfstnode\fP and
-\fBagnxtnode\fP are the usual functions for scanning
-node lists. When node sets are flattened it is permissible to
-call \fBagfstnode\fP and \fBagnxtnode\fP, but conflicting
-attempts to insert, delete, or search for nodes cause a runtime error.
-.SH "EDGES"
-.PP
-An abstract edge is represented by two edge structs.
-There is one pointing to each terminal node, and
-residing in an edge list of the opposite node.
-The object tag distinguishes between these otherwise
-symmetric records, to allow obtaining head and tail.
-If a graph has multi-edges between the same nodes,
-the name field serves as a secondary key.
-
-\fBagedge\fP searches in a graph of subgraph for an
-edge between the given endpoints (with an optional
-multi-edge selector name) and returns it if found.
-Otherwise, if \fBcreateflag\fP is boolean true,
-a new edge is created and returned: otherwise
-a nil pointer is returned. If the \fBname\fP
-is \f5(char*)0\fP then an anonymous internal
-value is generated.
-\fBagfstin\fP, \fBagnxtint\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. In traversing lists, \f5e->node\fP
-always points to the ``other'' node of the edge,
-To resolve ambiguity between in- and out-edge structs,
-\fBaghead\fP and \fBagtail\fP are macros or inline
-functions to find endpoints by checking object tags.
-\fBagopp\fP returns the ``opposite'' edge struct.
-Similarly \fBagfout\fP, \fBagfin\fP, and \fBagnedge\fP
-operate on flattened edge lists.
-
-.SH "STRING ATTRIBUTES"
-Programmer-defined values may be dynamically
-attached to graphs, subgraphs, nodes, and edges. Such
-values are either uninterpreted binary records
-(for implementing efficient algorithms)
-or character string data (for I/O).
-String attributes are handled automatically in reading
-and writing graph files. Uninterpreted records are
-ignored; any desired conversion must be coded
-explicitly by application programmers.
-
-A string attribute is identified by name and by
-an internal symbol table entry (\fBAgsym_t\fP) created by Libagraph.
-Attributes of nodes, edges, and graphs (with their subgraphs)
-have separate namespaces. The contents of an \fBAgsym_t\fP
-is listed below, followed by primitives to operate on string
-attributes.
-.P0
-typedef struct Agsym_s { /* symbol in one of the above dictionaries */
- Dtlink_t link;
- char *name; /* attribute's name */
- char *defval; /* its default value for initialization */
- int id; /* its index in attr[] */
-} Agsym_t;
-.P1
-.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.
-
-\fBagdictof\fP returns a Libdict set of all the attributes
-of a given kind. \fBagdictsym\fP is a utility function that
-finds an entry in one of these dictionary sets.
-
-\fBagget\fP and \fBagset\fP read and update string attributes.
-The first argument should be a graph, node, or edge struct pointer.
-\fBagxset\fP and \fBagxset\fP take a symbol table entry reference
-instead of a name, to avoid the cost of looking up attribute names
-inside loops.
-Note that Libagraph performs its own storage management of strings.
-The calling program does not need to dynamically allocate storage.
-
-.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 have a common header
-as shown below.
-.P0
-typedef struct Agrec_s {
- char *name;
- struct Agrec_s *next;
- /* programmer-defined follows */
-} Agrec_t;
-.P1
-Records are created and managed by Libagraph. In each graph, node,
-or edge, \fBdata\fR points to a circular list of records.
-The \fBname\fP field distinguishes various types of records, and is
-programmer defined (Libagraph reserves the prefix \fB_ag\fR).
-\fBnext\fP stores the list pointers.
-The remainder of a record may contain application-dependent fields.
-\fBagnewrec\fP creates one new record of the given size and attaches
-it to the given object (graph, node, or edge). \fBagdelrec\fP
-is the corresponding function to delete records. \fBaggetrec\fP
-finds a record with the given name.
-
-To allow referencing application-dependent data without function
-calls or linear search, Libagraph allows setting and locking the
-\fBdata\fP field of a graph, node, or edge on a particular record.
-The \fBmove_to_front\fP flag may be \fBAG_MTF_FALSE\fP,
-\fBAG_MTF_SOFT\fP, or \fBAG_MTF_HARD\fP accordingly.
-The \fBAG_MTF_SOFT\fP field is only a hint that decreases
-overhead in subsequent calls of \fBaggetrec\fP;
-\fBAG_MTF_HARD\fP guarantees that a lock was obtained.
-To release locks, use \fBAG_MTF_SOFT\fP or \fBAG_MTF_FALSE\fP.
-Use of this feature implies cooperation or at least isolation
-from other functions also using the move-to-front convention.
-
-A cast (generally using a macro or inline function)
-is then needed to convert the \fBdata\fP pointer to
-an appropriate programmer-defined type.
-
-.SH "DISCIPLINES"
-Programmer-defined disciplines customize certain resources-
-ID namespace, memory, and I/O - needed by Libagraph.
-A discipline struct (or NIL) is passed at graph creation time.
-.P0
-struct Agdisc_s { /* user's discipline */
- Agmemdisc_t *mem;
- Agiddisc_t *id;
- Agiodisc_t *io;
-} ;
-.P1
-A default discipline is supplied when NIL is given for
-any of these fields.
-
-An ID allocator discipline allows a client to control assignment
-of IDs (uninterpreted 32-bit 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); /* associated with a graph */
- int (*map)(void *state, int objtype, char *str, ulong *id, int createflag);
- int (*alloc)(void *state, int objtype, ulong id);
- void (*free)(void *state, int objtype, ulong id);
- char *(*print)(void *state, int objtype, ulong id);
- void (*close)(void *state);
-} ;
-.P1
-
-\f5open\fP permits the ID discipline to initialize any data
-structures that maintains per individual graph.
-Its return value is then passed as the first argument to
-all subsequent ID manager calls.
-
-\f5alloc\fP informs the ID manager that Libagraph 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).
-
-\f5free\fP is called to inform the ID manager that the
-object labeled with the given ID is about to go out of existence.
-
-\f5map\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 \f5result\fP. There are four cases:
-.PP
-\f5name != NULL\fP and \f5createflag == 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 \f5print\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):
-.PP
-\f5name == NULL\fP and \f5createflag == 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.)
-.PP
-\f5name != NULL\fP and \f5createflag == 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 32 bit values.)
-.PP
-\f5name == NULL\fP and \f5createflag == 0\fP: forbidden.
-.PP
-\f5print\fP should return
-\f5print\fP is allowed to return a pointer to a static buffer;
-a caller must copy its value if needed past subsequent calls.
-\f5NULL\fP should be returned by ID managers that do not map names.
-.PP
-The \f5map\fP and \f5alloc\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.
-.P0
-struct Agiodisc_s {
- int (*fread)(void *chan, char *buf, int bufsize);
- int (*putstr)(void *chan, char *str);
- int (*flush)(void *chan); /* sync */
- /* error messages? */
-} ;
-
-struct Agmemdisc_s { /* memory allocator */
- void *(*open)(void); /* 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);
-} ;
-.P1
-
-.SH "EXAMPLE PROGRAM"
-.P0
-#include <graphviz/agraph.h>
-typedef struct mydata_s {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*))) {
- /* dtsize() is a Libdict primitive */
- fprintf(stderr,"%s has %d node attributes\n",
- dtsize(agdictof(g,AGNODE)));
- attr = agattr(g,AGNODE,"color","blue");
-
- /* create a new graph */
- 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++;
-
- /* using inline functions or macros, attach records to edges */
- agflatten(g);
- for (v = agfstn(g); v; v = agnxtn(v))
- for (e = agfout(v); e; e; = agnxte(e)) {
- p = (mydata*) agnewrec(g,e,"mydata",sizeof(mydata));
- p->x = 27; /* meaningless example */
- }
- }
-}
-.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"
-Libcdt(3)
-
-.SH "BUGS"
-The root graph \fBname\fP is treated as a comment.
-
-There is no way to delete string attributes or modify edge keys.
-
-Strings and uninterpreted records could be treatly more uniformly.
-
-The library is not thread-safe.
-
-.SH "AUTHOR"
-Stephen North, north@research.att.com, AT&T Research.
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#ifndef ATT_GRAPH_H
-#define ATT_GRAPH_H
-
-#include <cdt.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-#ifndef TRUE
-#define TRUE (!FALSE)
-#endif
-#ifndef NOT
-#define NOT(x) (!(x))
-#endif
-#ifndef NIL
-#define NIL(type) ((type)0)
-#endif
-#define NILgraph NIL(Agraph_t*)
-#define NILnode NIL(Agnode_t*)
-#define NILedge NIL(Agedge_t*)
-#define NILsym NIL(Agsym_t*)
-
-/* forward struct type declarations */
- typedef struct Agtag_s Agtag_t;
- typedef struct Agobj_s Agobj_t; /* generic object header */
- typedef struct Agraph_s Agraph_t; /* graph, subgraph (or hyperedge) */
- typedef struct Agnode_s Agnode_t; /* node (atom) */
- typedef struct Agedge_s Agedge_t; /* node pair */
- typedef struct Agdesc_s Agdesc_t; /* graph descriptor */
- typedef struct Agmemdisc_s Agmemdisc_t; /* memory allocator */
- typedef struct Agiddisc_s Agiddisc_t; /* object ID allocator */
- typedef struct Agiodisc_s Agiodisc_t; /* IO services */
- typedef struct Agdisc_s Agdisc_t; /* union of client discipline methods */
- typedef struct Agdstate_s Agdstate_t; /* client state (closures) */
- typedef struct Agsym_s Agsym_t; /* string attribute descriptors */
- typedef struct Agattr_s Agattr_t; /* string attribute container */
- typedef struct Agcbdisc_s Agcbdisc_t; /* client event callbacks */
- typedef struct Agcbstack_s Agcbstack_t; /* enclosing state for cbdisc */
- typedef struct Agclos_s Agclos_t; /* common fields for graph/subgs */
- typedef struct Agrec_s Agrec_t; /* generic runtime record */
- typedef struct Agdatadict_s Agdatadict_t; /* set of dictionaries per graph */
- typedef struct Agedgepair_s Agedgepair_t;
-
-/* Header of a user record. These records are attached by client programs
-dynamically at runtime. A unique string ID must be given to each record
-attached to the same object. Libgraph has functions to create, search for,
-and delete these records. The records are maintained in a circular list,
-with obj->data pointing somewhere in the list. The search function has
-an option to lock this pointer on a given record. The application must
-be written so only one such lock is outstanding at a time. */
-
- struct Agrec_s {
- char *name;
- Agrec_t *next;
- /* following this would be any programmer-defined data */
- };
-
-/* Object tag for graphs, nodes, and edges. While there may be several structs
-for a given node or edges, there is only one unique ID (per main graph). */
- struct Agtag_s {
- unsigned objtype:2; /* see literal tags below */
- unsigned mtflock:1; /* move-to-front lock, see above */
- unsigned attrwf:1; /* non-default attrs written */
- unsigned seq:(sizeof(unsigned) * 8 - 6); /* sequence no. */
- unsigned long id; /* client ID */
- };
-
- /* object tags */
-#define AGRAPH 0 /* can't exceed 2 bits. see Agtag_t. */
-#define AGNODE 1
-#define AGOUTEDGE 2
-#define AGINEDGE 3 /* (1 << 1) indicates an edge tag. */
-#define AGEDGE AGOUTEDGE /* synonym in object kind args */
-
- /* a generic graph/node/edge header */
- struct Agobj_s { /* 7 words *//* seq_link must be first! */
- Dtlink_t seq_link; /* link for ordering by local sequence */
- Dtlink_t id_link; /* link for ordering by global id */
- Agtag_t tag;
- Agrec_t *data;
- };
-
-#define AGTAG(obj) (((Agobj_t*)(obj))->tag)
-#define AGTYPE(obj) (AGTAG(obj).objtype)
-#define AGID(obj) (AGTAG(obj).id)
-#define AGSEQ(obj) (AGTAG(obj).seq)
-#define AGATTRWF(obj) (AGTAG(obj).attrwf)
-#define AGDATA(obj) (((Agobj_t*)(obj))->data)
-
-/* This is the node struct allocated per graph (or subgraph). It resides
-in the n_dict of the graph. The node set is maintained by libdict, but
-transparently to libgraph callers. Every node may be given an optional
-string name at its time of creation, or it is permissible to pass NIL(char*)
-for the name. */
-
- struct Agnode_s { /* 12 words */
- Agobj_t base;
- Agraph_t *g;
- Dtlink_t *outid, *inid; /* in- and out-edge trees by index */
- Agedge_t *out, *in; /* in- and out-edge trees by seq */
- };
-
- struct Agedge_s { /* 8 words, but allocated in pairs -> 16 words */
- Agobj_t base;
- Agnode_t *node; /* the endpoint node */
- };
-
- struct Agedgepair_s {
- Agedge_t out, in;
- };
-
- struct Agdesc_s { /* graph descriptor */
- unsigned directed:1; /* if edges are assymmetric */
- unsigned strict:1; /* if and self, multi-edges forbidden */
- unsigned flatlock:1; /* if sets are flattened into lists */
- unsigned maingraph:1; /* if this is the top level graph */
- unsigned has_cmpnd:1; /* if may contain collapsed nodes */
- unsigned no_write:1; /* if a temporary subgraph */
- unsigned has_attrs:1; /* if string attr tables should be initialized */
- };
-
-/* disciplines for external resources needed by libgraph */
-
- struct Agmemdisc_s { /* memory allocator */
- void *(*open) (void); /* 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);
- };
-
- struct Agiddisc_s { /* object ID allocator */
- void *(*open) (Agraph_t * g); /* 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);
- };
-
- struct Agiodisc_s {
- int (*afread) (void *chan, char *buf, int bufsize);
- int (*putstr) (void *chan, char *str);
- int (*flush) (void *chan); /* sync */
- /* error messages? */
- };
-
- struct Agdisc_s { /* user's discipline */
- Agmemdisc_t *mem;
- Agiddisc_t *id;
- Agiodisc_t *io;
- };
-
- /* default resource disciplines */
-#if !defined(_BLD_agraph) && defined(GVDLL)
-#define extern __declspec(dllimport)
-#endif
-
- extern Agmemdisc_t AgMemDisc;
- extern Agiddisc_t AgIdDisc;
- extern Agiodisc_t AgIoDisc;
-
- extern Agdisc_t AgDefaultDisc;
-#undef extern
-
- struct Agdstate_s {
- void *mem;
- void *id;
- /* IO must be initialized and finalized outside Libgraph,
- * and channels (FILES) are passed as void* arguments. */
- };
-
- typedef void (*agobjfn_t) (Agobj_t * obj, void *arg);
- typedef void (*agobjupdfn_t) (Agobj_t * obj, void *arg, Agsym_t * sym);
-
- struct Agcbdisc_s {
- struct {
- agobjfn_t ins;
- agobjupdfn_t mod;
- agobjfn_t del;
- } graph, node, edge;
- };
-
- struct Agcbstack_s { /* object event callbacks */
- Agcbdisc_t *f; /* methods */
- void *state; /* closure */
- Agcbstack_t *prev; /* kept in a stack, unlike other disciplines */
- };
-
- struct Agclos_s {
- Agdisc_t disc; /* resource discipline functions */
- Agdstate_t state; /* resource closures */
- Dict_t *strdict; /* shared string dict */
- unsigned long seq[3]; /* local object sequence number counter */
- Agcbstack_t *cb; /* user and system callback function stacks */
- unsigned char callbacks_enabled; /* issue user callbacks or hold them? */
- Dict_t *lookup_by_name[3];
- Dict_t *lookup_by_id[3];
- };
-
- struct Agraph_s { /* 14 words */
- Agobj_t base;
- Agdesc_t desc;
- Dict_t *n_seq; /* the node set in sequence */
- Dict_t *n_id; /* the node set indexed by ID */
- Dict_t *e_seq; /* template for edge set operations */
- Dict_t *e_id; /* template for edge set operations */
- Dict_t *g_dict; /* subgraphs - descendants */
- Agraph_t *parent, *root; /* subgraphs - ancestors */
- Agclos_t *clos; /* shared resources */
- };
-
-
-#if defined(_PACKAGE_ast)
-/* fine control of object callbacks */
-# if defined(_BLD_agraph) && defined(__EXPORT__)
-# define extern __EXPORT__
-# endif
-# if !defined(_BLD_agraph) && defined(__IMPORT__)
-# define extern __IMPORT__
-# endif
-#endif
-
- extern void agpushdisc(Agraph_t * g, Agcbdisc_t * disc, void *state);
- extern int agpopdisc(Agraph_t * g, Agcbdisc_t * disc);
- extern int agcallbacks(Agraph_t * g, int flag); /* return prev value */
-
-/* graphs */
- extern Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * disc);
- extern int agclose(Agraph_t * g);
- extern Agraph_t *agread(void *chan, Agdisc_t * disc);
- extern void agreadline(int);
- extern void agsetfile(char *);
- extern Agraph_t *agconcat(Agraph_t * g, void *chan, Agdisc_t * disc);
- extern int agwrite(Agraph_t * g, void *chan);
- extern void agflatten(Agraph_t * g, int flag);
- extern int agisflattened(Agraph_t * g);
- extern int agisdirected(Agraph_t * g);
- extern int agisundirected(Agraph_t * g);
- extern int agisstrict(Agraph_t * g);
-
-/* nodes */
- extern Agnode_t *agnode(Agraph_t * g, char *name, int createflag);
- extern Agnode_t *agidnode(Agraph_t * g, unsigned long id,
- int createflag);
- extern Agnode_t *agsubnode(Agraph_t * g, Agnode_t * n, int createflag);
- extern Agnode_t *agfstnode(Agraph_t * g);
- extern Agnode_t *agnxtnode(Agnode_t * n);
-
-/* edges */
- extern Agedge_t *agedge(Agnode_t * t, Agnode_t * h, char *name,
- int createflag);
- extern Agedge_t *agidedge(Agnode_t * t, Agnode_t * h, unsigned long id,
- int createflag);
- extern Agedge_t *agsubedge(Agraph_t * g, Agedge_t * e, int createflag);
- extern Agedge_t *agfstin(Agnode_t * n);
- extern Agedge_t *agnxtin(Agedge_t * e);
- extern Agedge_t *agfstout(Agnode_t * n);
- extern Agedge_t *agnxtout(Agedge_t * e);
- extern Agedge_t *agfstedge(Agnode_t * n);
- extern Agedge_t *agnxtedge(Agedge_t * e, Agnode_t * n);
-
-/* generic */
- extern Agraph_t *agraphof(void *);
- extern char *agnameof(void *);
- extern int agrelabel(void *obj, char *name); /* scary */
- extern int agrelabel_node(Agnode_t * n, char *newname);
- extern int agdelete(Agraph_t * g, void *obj);
- extern long agdelsubg(Agraph_t * g, Agraph_t * sub); /* could be agclose */
- extern int agdelnode(Agnode_t * arg_n);
- extern int agdeledge(Agedge_t * arg_e);
- extern int agisarootobj(void *);
- extern Agobj_t *agrebind(Agraph_t * g, Agobj_t * obj);
-
-/* strings */
- extern char *agstrdup(Agraph_t *, char *);
- extern char *agstrdup_html(Agraph_t *, char *);
- extern int aghtmlstr(char *);
- extern char *agstrbind(Agraph_t * g, char *);
- extern int agstrfree(Agraph_t *, char *);
- extern char *agcanonstr(char *, char *);
- extern char *agcanonStr(char*);
-
-/* definitions for dynamic string attributes */
- struct Agattr_s { /* dynamic string attributes */
- Agrec_t h; /* common data header */
- Dict_t *dict; /* shared dict to interpret attr field */
- char **str; /* the attribute string values */
- };
-
- struct Agsym_s { /* symbol in one of the above dictionaries */
- Dtlink_t link;
- char *name; /* attribute's name */
- char *defval; /* its default value for initialization */
- int id; /* its index in attr[] */
- int kind; /* referent object type */
- };
-
- struct Agdatadict_s { /* set of dictionaries per graph */
- Agrec_t h; /* installed in list of graph recs */
- struct {
- Dict_t *n, *e, *g;
- } dict;
- };
-
- extern Agsym_t *agattr(Agraph_t * g, int kind, char *name,
- char *value);
- extern Agsym_t *agattrsym(void *obj, char *name);
- extern Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr);
- extern void *agbindrec(void *obj, char *name, unsigned int size,
- int move_to_front);
- extern Agrec_t *aggetrec(void *obj, char *name, int move_to_front);
- extern int agdelrec(void *obj, char *name);
- extern void aginit(Agraph_t * g, int kind, char *rec_name,
- int rec_size, int move_to_front);
- extern void agclean(Agraph_t * g, int kind, char *rec_name);
-
- extern char *agget(void *obj, char *name);
- extern char *agxget(void *obj, Agsym_t * sym);
- extern int agset(void *obj, char *name, char *value);
- extern int agxset(void *obj, Agsym_t * sym, char *value);
-
-/* defintions for subgraphs */
- extern Agraph_t *agsubg(Agraph_t * g, char *name, int cflag); /* constructor */
- extern Agraph_t *agidsubg(Agraph_t * g, unsigned long id, int cflag); /* constructor */
- extern Agraph_t *agfstsubg(Agraph_t * g), *agnxtsubg(Agraph_t * subg);
- extern Agraph_t *agparent(Agraph_t * g), *agroot(Agraph_t * g);
-
-/* set cardinality */
- extern int agnnodes(Agraph_t * g), agnedges(Agraph_t * g);
- extern int agdegree(Agnode_t * n, int in, int out);
-
-/* memory */
- extern void *agalloc(Agraph_t * g, size_t size);
- extern void *agrealloc(Agraph_t * g, void *ptr, size_t oldsize,
- size_t size);
- extern void agfree(Agraph_t * g, void *ptr);
- extern struct _vmalloc_s *agheap(Agraph_t * g);
-
-/* an engineering compromise is a joy forever */
- extern void aginternalmapclearlocalnames(Agraph_t * g);
-
-#define agnew(g,t) ((t*)agalloc(g,sizeof(t)))
-#define agnnew(g,n,t) ((t*)agalloc(g,(n)*sizeof(t)))
-
-/* error handling */
- extern void agerror(int code, char *str);
-#define AGERROR_SYNTAX 1 /* error encountered in lexing or parsing */
-#define AGERROR_MEMORY 2 /* out of memory */
-#define AGERROR_UNIMPL 3 /* unimplemented feature */
-#define AGERROR_MTFLOCK 4 /* move to front lock has been set */
-#define AGERROR_CMPND 5 /* conflict in restore_endpoint() */
-#define AGERROR_BADOBJ 6 /* passed an illegal pointer */
-#define AGERROR_IDOVFL 7 /* object ID overflow */
-#define AGERROR_FLAT 8 /* attempt to break a flat lock */
-#define AGERROR_WRONGGRAPH 9 /* mismatched graph and object */
-
-/* abbreviations, convenience */
-
-#define AGFIRSTNODE(g) ((Agnode_t*)dtfirst((g)->n_seq))
-#define AGPREVNODE(n) ((Agnode_t*)((n)->base.seq_link.hl._left))
-#define AGNEXTNODE(n) ((Agnode_t*)((n)->base.seq_link.right))
-#define AGFSTOUT(n) ((Agedge_t*)((n)->out))
-#define AGFSTIN(n) ((Agedge_t*)((n)->in))
-#define AGPREV(e) ((Agedge_t*)((e)->base.seq_link.hl._left))
-#define AGNXTE(e) ((Agedge_t*)((e)->base.seq_link.right))
-/* this assumes that e[0] is out and e[1] is inedge, see edgepair in edge.c */
-#define AGIN2OUT(e) ((e)-1)
-#define AGOUT2IN(e) ((e)+1)
-#define AGOPP(e) ((AGTYPE(e)==AGINEDGE)?AGIN2OUT(e):AGOUT2IN(e))
-#define AGMKOUT(e) (AGTYPE(e) == AGOUTEDGE? (e): AGIN2OUT(e))
-#define AGMKIN(e) (AGTYPE(e) == AGINEDGE? (e): AGOUT2IN(e))
-#define AGTAIL(e) (AGMKIN(e)->node)
-#define AGHEAD(e) (AGMKOUT(e)->node)
-#define agtail(e) AGTAIL(e)
-#define aghead(e) AGHEAD(e)
-#define agopp(e) AGOPP(e)
-
-#if defined(_PACKAGE_ast)
-# if !defined(_BLD_agraph) && defined(__IMPORT__)
-# define extern __IMPORT__
-# endif
-#endif
-#if !defined(_BLD_agraph) && defined(GVDLL)
-#define extern __declspec(dllimport)
-#endif
-
- extern Agdesc_t Agdirected, Agstrictdirected, Agundirected,
- Agstrictundirected;
-
-#undef extern
-#if defined(_PACKAGE_ast)
- _END_EXTERNS_
-#endif
-#ifdef __cplusplus
-}
-#endif
-#endif
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/* The following functions take a graph and a template (node/edge/graph)
- * and return the object representing the template within the local graph.
- */
-static Agobj_t *subnode_search(Agraph_t * sub, Agobj_t * n)
-{
- if (agraphof(n) == sub)
- return n;
- return (Agobj_t *) agsubnode(sub, (Agnode_t *) n, FALSE);
-}
-
-static Agobj_t *subedge_search(Agraph_t * sub, Agobj_t * e)
-{
- if (agraphof(e) == sub)
- return e;
- return (Agobj_t *) agsubedge(sub, (Agedge_t *) e, FALSE);
-}
-
-static Agobj_t *subgraph_search(Agraph_t * sub, Agobj_t * g)
-{
- NOTUSED(g);
- return (Agobj_t *) sub;
-}
-
-/* recursively apply objfn within the hierarchy of a graph.
- * if obj is a node or edge, it and its images in every subg are visited.
- * if obj is a graph, then it and its subgs are visited.
- */
-static void rec_apply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
- agobjsearchfn_t objsearch, int preorder)
-{
- Agraph_t *sub;
- Agobj_t *subobj;
-
- if (preorder)
- fn(obj, arg);
- for (sub = agfstsubg(g); sub; sub = agnxtsubg(sub)) {
- if ((subobj = objsearch(sub, obj)))
- rec_apply(sub, subobj, fn, arg, objsearch, preorder);
- }
- if (NOT(preorder))
- fn(obj, arg);
-}
-
-/* external entry point (this seems to be one of those ineffective
- * comments censured in books on programming style) */
-int agapply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg,
- int preorder)
-{
- Agobj_t *subobj;
-
- agobjsearchfn_t objsearch;
- switch (AGTYPE(obj)) {
- case AGRAPH:
- objsearch = subgraph_search;
- break;
- case AGNODE:
- objsearch = subnode_search;
- break;
- case AGOUTEDGE:
- case AGINEDGE:
- objsearch = subedge_search;
- break;
- default:
- abort();
- }
- if ((subobj = objsearch(g, obj))) {
- rec_apply(g, subobj, fn, arg, objsearch, preorder);
- return SUCCESS;
- } else
- return FAILURE;
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/*
- * dynamic attributes
- */
-
-/* to create a graph's data dictionary */
-
-#define MINATTR 4 /* minimum allocation */
-
-static void freesym(Dict_t * d, Void_t * obj, Dtdisc_t * disc);
-
-Dtdisc_t AgDataDictDisc = {
- offsetof(Agsym_t, name), /* use symbol name as key */
- -1,
- offsetof(Agsym_t, link),
- NIL(Dtmake_f),
- freesym,
- NIL(Dtcompar_f),
- NIL(Dthash_f)
-};
-
-static char DataDictName[] = "_AG_datadict";
-static void init_all_attrs(Agraph_t * g);
-
-Agdatadict_t *agdatadict(Agraph_t * g)
-{
- Agdatadict_t *rv;
- while ((rv = (Agdatadict_t *) aggetrec(g, DataDictName, FALSE))
- == NIL(Agdatadict_t *))
- init_all_attrs(g);
- return rv;
-}
-
-Dict_t *agdictof(Agraph_t * g, int kind)
-{
- Agdatadict_t *dd;
- Dict_t *dict;
-
- dd = agdatadict(g);
- switch (kind) {
- case AGRAPH:
- dict = dd->dict.g;
- break;
- case AGNODE:
- dict = dd->dict.n;
- break;
- case AGINEDGE:
- case AGOUTEDGE:
- dict = dd->dict.e;
- break;
- default:
- abort();
- }
- return dict;
-}
-
-static Agdatadict_t *agmakedatadict(Agraph_t * g)
-{
- Agraph_t *par;
- Agdatadict_t *parent_dd, *dd;
-
- dd = (Agdatadict_t *) agbindrec(g, DataDictName, sizeof(Agdatadict_t),
- FALSE);
- dd->dict.n = agdtopen(g, &AgDataDictDisc, Dttree);
- dd->dict.e = agdtopen(g, &AgDataDictDisc, Dttree);
- dd->dict.g = agdtopen(g, &AgDataDictDisc, Dttree);
- if ((par = agparent(g))) {
- parent_dd = agdatadict(par);
- assert(dd != parent_dd);
- dtview(dd->dict.n, parent_dd->dict.n);
- dtview(dd->dict.e, parent_dd->dict.e);
- dtview(dd->dict.g, parent_dd->dict.g);
- }
- return dd;
-}
-
-Agsym_t *agnewsym(Agraph_t * g, char *name, char *value, int id, int kind)
-{
- Agsym_t *sym;
- sym = agalloc(g, sizeof(Agsym_t));
- sym->kind = kind;
- sym->name = agstrdup(g, name);
- sym->defval = agstrdup(g, value);
- sym->id = id;
- return sym;
-}
-
- /* look up or update a value associated with an object. */
-Agsym_t *agdictsym(Dict_t * dict, char *name)
-{
- Agsym_t key;
- key.name = (char *) name;
- return (Agsym_t *) dtsearch(dict, &key);
-}
-
-/* look up attribute in local dictionary with no view pathing */
-Agsym_t *aglocaldictsym(Dict_t * dict, char *name)
-{
- Agsym_t *rv;
- Dict_t *view;
-
- view = dtview(dict, NIL(Dict_t *));
- rv = agdictsym(dict, name);
- dtview(dict, view);
- return rv;
-}
-
-Agsym_t *agattrsym(void *obj, char *name)
-{
- Agattr_t *data;
-
- data = agattrrec((Agobj_t *) obj);
- return (data ? agdictsym(data->dict, name) : NILsym);
-}
-
-/* to create a graph's, node's edge's string attributes */
-
-char *AgDataRecName = "_AG_strdata";
-
-static int topdictsize(Agobj_t * obj)
-{
- return dtsize(agdictof(agroot(agraphof(obj)), AGTYPE(obj)));
-}
-
-static Agrec_t *agmakeattrs(void *obj, int norecur)
-{
- int sz;
- Agattr_t *rec;
- Agsym_t *sym;
- Agraph_t *g;
- Dict_t *datadict;
-
- g = agraphof(obj);
- rec =
- agrealbindrec(obj, AgDataRecName, sizeof(Agattr_t), FALSE,
- norecur);
- datadict = agdictof(g, AGTYPE(obj));
- if (rec->dict == NIL(Dict_t *)) {
- rec->dict = datadict;
- /* don't malloc(0) */
- sz = topdictsize(obj);
- if (sz < MINATTR)
- sz = MINATTR;
- rec->str = agalloc(g, sz * sizeof(char *));
- /* doesn't call agxset() so no obj-modified callbacks occur */
- for (sym = (Agsym_t *) dtfirst(datadict); sym;
- sym = (Agsym_t *) dtnext(datadict, sym))
- rec->str[sym->id] = agstrdup(g, sym->defval);
- } else {
- assert(rec->dict == datadict);
- }
- return (Agrec_t *) rec;
-}
-
-
-static void freeattr(Agobj_t * obj, Agattr_t * attr)
-{
- int i, sz;
- Agraph_t *g;
-
- g = agraphof(obj);
- sz = topdictsize(obj);
- for (i = 0; i < sz; i++)
- agstrfree(g, attr->str[i]);
- agfree(g, attr->str);
-}
-
-static void freesym(Dict_t * d, Void_t * obj, Dtdisc_t * disc)
-{
- Agsym_t *sym;
-
- NOTUSED(d);
- sym = (Agsym_t *) obj;
- NOTUSED(disc);
- agstrfree(Ag_G_global, sym->name);
- agstrfree(Ag_G_global, sym->defval);
- agfree(Ag_G_global, sym);
-}
-
-Agattr_t *agattrrec(void *obj)
-{
- return (Agattr_t *) aggetrec(obj, AgDataRecName, FALSE);
-}
-
-
-static void addattr(Agobj_t * obj, Agsym_t * sym)
-{
- Agattr_t *attr;
- Agraph_t *g;
-
- g = agraphof(obj);
- attr = (Agattr_t *) agattrrec(obj);
- assert(attr != NIL(Agattr_t *));
- if (sym->id >= MINATTR)
- attr->str = (char **) AGDISC(g, mem)->resize(AGCLOS(g, mem),
- attr->str,
- sym->id *
- sizeof(char *),
- (sym->id +
- 1) * sizeof(char *));
- attr->str[sym->id] = agstrdup(g, sym->defval);
- /* agmethod_upd(g,obj,sym); JCE and GN didn't like this. */
-}
-
-
-/*
- * create or update an existing attribute and return its descriptor.
- * if the new value is NIL(char*), this is only a search, no update.
- * when a new attribute is created, existing graphs/nodes/edges
- * receive its default value.
- */
-Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value)
-{
- Agraph_t *root;
- Agsym_t *lsym, *rsym;
- Dict_t *ldict, *rdict;
- Agnode_t *n;
- Agedge_t *e;
-
- ldict = agdictof(g, kind);
- lsym = aglocaldictsym(ldict, name);
- root = agroot(g);
- if (lsym) {
- /* this attr was previously defined in this graph */
- if (value) {
- agstrfree(g, lsym->defval);
- lsym->defval = agstrdup(g, value);
- }
- } else { /* not previously defined here */
- rsym = agdictsym(ldict, name); /* viewpath up to root */
- if (value) { /* need to define */
- if (rsym) {
- lsym = agnewsym(g, name, value, rsym->id, kind);
- dtinsert(ldict, lsym);
- } else { /* just define globally */
- rdict = agdictof(root, kind);
- lsym = rsym =
- agnewsym(g, name, value, dtsize(rdict), kind);
- dtinsert(rdict, rsym);
-
- switch (kind) {
- case AGRAPH:
- agapply(root, (Agobj_t *) root, (agobjfn_t) addattr,
- lsym, TRUE);
- break;
- case AGNODE:
- for (n = agfstnode(root); n; n = agnxtnode(n))
- addattr((Agobj_t *) n, lsym);
- break;
- case AGINEDGE:
- case AGOUTEDGE:
- for (n = agfstnode(root); n; n = agnxtnode(n))
- for (e = agfstout(n); e; e = agnxtout(e))
- addattr((Agobj_t *) e, lsym);
- break;
- }
- }
- agmethod_upd(g, g, lsym); /* JCE and GN wanted this instead */
- } else
- return rsym;
- }
- /* in graphs, defaults and actual values are always the same.
- * see also agxset() where graph attrs are handled. therefore
- * agxset() must not call agattr() in its implementation
- */
- if (lsym && value && (kind == AGRAPH))
- agxset(g, lsym, value);
- return lsym;
-}
-
-Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr)
-{
- Dict_t *d;
- Agsym_t *rv;
-
- d = agdictof(g, kind);
- if (attr)
- rv = (Agsym_t *) dtnext(d, attr);
- else
- rv = (Agsym_t *) dtfirst(d);
- return rv;
-}
-
-/* Create or delete attributes associated with an object */
-
-void agraphattr_init(Agraph_t * g, int norecur)
-{
- /* Agdatadict_t *dd; */
- /* Agrec_t *attr; */
-
- g->desc.has_attrs = 1;
- /* dd = */ agmakedatadict(g);
- /* attr = */ agmakeattrs(g, norecur);
-}
-
-void agraphattr_delete(Agraph_t * g)
-{
- Agdatadict_t *dd;
- Agattr_t *attr;
-
- Ag_G_global = g;
- if ((attr = agattrrec(g))) {
- freeattr((Agobj_t *) g, attr);
- agdelrec(g, attr->h.name);
- }
-
- if ((dd = agdatadict(g))) {
- agdtclose(g, dd->dict.n);
- agdtclose(g, dd->dict.e);
- agdtclose(g, dd->dict.g);
- agdelrec(g, dd->h.name);
- }
-}
-
-void agnodeattr_init(Agnode_t * n, int norecur)
-{
- Agattr_t *data;
-
- data = agattrrec(n);
- if ((!data) || (!data->dict))
- (void) agmakeattrs(n, norecur);
-}
-
-void agnodeattr_delete(Agnode_t * n)
-{
- Agattr_t *rec;
-
- if ((rec = agattrrec(n))) {
- freeattr((Agobj_t *) n, rec);
- agdelrec(n, AgDataRecName);
- }
-}
-
-void agedgeattr_init(Agedge_t * e, int norecur)
-{
- Agattr_t *data;
-
- data = agattrrec(e);
- if ((!data) || (!data->dict))
- (void) agmakeattrs(e, norecur);
-}
-
-void agedgeattr_delete(Agedge_t * e)
-{
- Agattr_t *rec;
-
- if ((rec = agattrrec(e))) {
- freeattr((Agobj_t *) e, rec);
- agdelrec(e, AgDataRecName);
- }
-}
-
-char *agget(void *obj, char *name)
-{
- Agsym_t *sym;
- Agattr_t *data;
- char *rv;
-
- sym = agattrsym(obj, name);
- if (sym == NILsym)
- rv = "";
- else {
- data = agattrrec((Agobj_t *) obj);
- rv = (char *) (data->str[sym->id]);
- }
- return rv;
-}
-
-char *agxget(void *obj, Agsym_t * sym)
-{
- Agattr_t *data;
- char *rv;
-
- data = agattrrec((Agobj_t *) obj);
- assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
- rv = (char *) (data->str[sym->id]);
- return rv;
-}
-
-int agset(void *obj, char *name, char *value)
-{
- Agsym_t *sym;
- int rv;
-
- sym = agattrsym(obj, name);
- if (sym == NILsym)
- rv = FAILURE;
- else
- rv = agxset(obj, sym, value);
- return rv;
-}
-
-int agxset(void *obj, Agsym_t * sym, char *value)
-{
- Agraph_t *g;
- Agobj_t *hdr;
- Agattr_t *data;
- Agsym_t *lsym;
-
- g = agraphof(obj);
- hdr = (Agobj_t *) obj;
- data = agattrrec(hdr);
- assert((sym->id >= 0) && (sym->id < topdictsize(obj)));
- agstrfree(g, data->str[sym->id]);
- data->str[sym->id] = agstrdup(g, value);
- if (hdr->tag.objtype == AGRAPH) {
- /* also update dict default */
- Dict_t *dict;
- dict = agdatadict(g)->dict.g;
- if ((lsym = aglocaldictsym(dict, sym->name))) {
- agstrfree(g, lsym->defval);
- lsym->defval = agstrdup(g, value);
- } else {
- lsym = agnewsym(g, sym->name, value, sym->id, AGTYPE(hdr));
- dtinsert(dict, lsym);
- }
- }
- agmethod_upd(g, obj, sym);
- return SUCCESS;
-}
-
-/*
- * here we are attaching attributes to the already created graph objs.
- * presumably they were already initialized, so we don't invoke any
- * of the old methods.
- */
-static void init_all_attrs(Agraph_t * g)
-{
- Agraph_t *root;
- Agnode_t *n;
- Agedge_t *e;
-
- root = agroot(g);
- agapply(root, (Agobj_t *) root, (agobjfn_t) agraphattr_init,
- NIL(Agdisc_t *), TRUE);
- for (n = agfstnode(root); n; n = agnxtnode(n)) {
- agnodeattr_init(n, FALSE);
- for (e = agfstout(n); e; e = agnxtout(e)) {
- agedgeattr_init(e, FALSE);
- }
- }
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/*
- * provides "compound nodes" on top of base Libgraph.
- * a compound node behaves as both an ordinary node and a subgraph.
- * there are additional primitives to "hide" and "expose" its contents.
- *
- * you could think of these as hypergraphs, but there is an assymetry
- * in the operations we have chosen. i.e. nodes "own" their edges,
- * but nodes and interior edges are "owned by" the hyperedges.
- * also the subgraphs are nested, etc. the bottom line is that graphs
- * and hypergraphs are just sets, everything else here is convenience
- * and maintaining consistency.
- *
- * this package adds a primitive "agsplice" to move endpoints of edges.
- * this could be useful in other situations.
- */
-
-static char Descriptor_id[] = "AG_cmpnd";
-
-typedef struct Agcmpnode_s {
- Agrec_t hdr;
- Agraph_t *subg;
- int collapsed;
-} Agcmpnode_t;
-
-typedef struct Agcmpgraph_s {
- Agrec_t hdr;
- Agnode_t *node; /* its associated node */
- Dict_t *hidden_node_set;
-} Agcmpgraph_t;
-
-typedef struct save_e_s {
- Agnode_t *from, *to;
-} save_e_t;
-
-typedef struct save_stack_s {
- save_e_t *mem;
- int stacksize;
-} save_stack_t;
-
-typedef struct Agcmpedge_s {
- Agrec_t hdr;
- save_stack_t stack[2]; /* IN and OUT save stacks */
-} Agcmpedge_t;
-#define IN_STACK 0
-#define OUT_STACK 1
-
-static save_stack_t *save_stack_of(Agedge_t * e,
- Agnode_t * node_being_saved)
-{
- int i;
- Agcmpedge_t *edgerec;
- edgerec =
- (Agcmpedge_t *) agbindrec(e, Descriptor_id, sizeof(*edgerec),
- FALSE);
- if (node_being_saved == AGHEAD(e))
- i = IN_STACK;
- else
- i = OUT_STACK;
- return &(edgerec->stack[i]);
-}
-
-static void stackpush(save_stack_t * stk, Agnode_t * from, Agnode_t * to)
-{
- int i, osize, nsize;
-
- osize = (stk->stacksize) * sizeof(stk->mem);
- i = stk->stacksize++;
- nsize = (stk->stacksize) * sizeof(stk->mem);
- stk->mem = agrealloc(agraphof(from), stk->mem, osize, nsize);
- stk->mem[i].from = from;
- stk->mem[i].to = to;
-}
-
-static save_e_t stacktop(save_stack_t * stk)
-{
- save_e_t rv;
- if (stk->stacksize > 0)
- rv = stk->mem[stk->stacksize - 1];
- else
- rv.from = rv.to = NILnode;
- return rv;
-}
-
-/* note: doesn't give back mem, but stackpush() eventually does */
-static save_e_t stackpop(save_stack_t * stk)
-{
- save_e_t rv;
- rv = stacktop(stk);
- if (stk->stacksize > 0)
- stk->stacksize--;
- return rv;
-}
-
-typedef struct Agsplice_arg_s {
- int head_side;
- Agnode_t *target;
-} Agsplice_arg_t;
-
-/* perform a splice operation on an individual edge */
-static void splice(Agobj_t * obj, void *arg)
-{
- Agraph_t *g;
- Agedge_t *e, *opp;
- Agnode_t *target, *t, *h;
- Agedge_t **dict_of_del, **dict_of_ins, **dict_of_relabel;
- Agsplice_arg_t *spl;
-
- e = (Agedge_t *) obj;
- g = agraphof(e);
- t = AGTAIL(e);
- h = AGHEAD(e);
- opp = AGOPP(e);
- spl = arg;
- target = spl->target;
-
- /* set e to variant side, opp to invariant */
- if ((e->node == h) != spl->head_side) {
- Agedge_t *t = e;
- e = opp;
- opp = t;
- }
-
- if (spl->head_side) {
- dict_of_relabel = &(t->out);
- dict_of_del = &(h->in);
- dict_of_ins = &(target->in);
- } else {
- dict_of_relabel = &(h->in);
- dict_of_del = &(t->out);
- dict_of_ins = &(target->out);
- }
-
- agdeledgeimage(g, dict_of_del, opp);
- agdeledgeimage(g, dict_of_relabel, e);
- e->node = target;
- aginsedgeimage(g, dict_of_ins, opp);
- aginsedgeimage(g, dict_of_relabel, e);
-}
-
-int agsplice(Agedge_t * e, Agnode_t * target)
-{
- Agnode_t *t, *h;
- Agraph_t *g, *root;
- Agsplice_arg_t splice_arg;
-
-
- if ((e == NILedge) || (e->node == target))
- return FAILURE;
- g = agraphof(e);
- t = AGTAIL(e);
- h = AGHEAD(e);
- splice_arg.head_side = (e->node == h);
- splice_arg.target = target;
- root = agroot(g);
- agapply(root, (Agobj_t *) e, splice, &splice_arg, TRUE);
- return SUCCESS;
-}
-
-Agnode_t *agcmpnode(Agraph_t * g, char *name)
-{
- Agnode_t *n;
- Agraph_t *subg;
- n = agnode(g, name, TRUE);
- subg = agsubg(g, name);
- if (n && g && agassociate(n, subg))
- return n;
- else
- return NILnode;
-}
-
-int agassociate(Agnode_t * n, Agraph_t * sub)
-{
- Agcmpnode_t *noderec;
- Agcmpgraph_t *graphrec;
-
- if (agsubnode(sub, n, FALSE))
- return FAILURE; /* avoid cycles */
- noderec = agbindrec(n, Descriptor_id, sizeof(*noderec), FALSE);
- graphrec = agbindrec(sub, Descriptor_id, sizeof(*graphrec), FALSE);
- if (noderec->subg || graphrec->node)
- return FAILURE;
- noderec->subg = sub;
- graphrec->node = n;
- return SUCCESS;
-}
-
-/* a utility function for aghide */
-static void delete_outside_subg(Agraph_t * g, Agnode_t * node,
- Agraph_t * subg)
-{
- Agraph_t *s, **subglist;
- Agnode_t *n;
- Agcmpgraph_t *graphrec;
- Dict_t *d;
-
- if ((g != subg) && (n = agsubnode(g, (Agnode_t *) node, FALSE))) {
- dtdelete(g->n_dict, n);
-
- graphrec = agbindrec(g, Descriptor_id, sizeof(*graphrec), FALSE);
- if ((d = graphrec->hidden_node_set) == NIL(Dict_t *)) {
- /* use name disc. to permit search for hidden node by name */
- d = graphrec->hidden_node_set
- = agdtopen(g, &Ag_node_name_disc, Dttree);
- }
- dtinsert(d, n);
-
- subglist = agsubglist(g);
- while ((s = *subglist++))
- delete_outside_subg(s, node, subg);
- }
-}
-
-/*
- * when we hide a compound node (make it opaque)
- * 1. hide its nodes (option)
- * 2. hide the associated subgraph (option)
- * 3. remap edges to internal nodes (option)
- */
-int aghide(Agnode_t * cmpnode)
-{
- Agcmpnode_t *noderec;
- Agraph_t *g, *subg, *root;
- Agnode_t *n, *nn, *rootn;
- Agedge_t *e, *opp, *f;
-
- g = agraphof(cmpnode);
- /* skip operation if node is not compound, or hidden */
- if (agcmpgraph_of(cmpnode) == NILgraph)
- return FAILURE;
- noderec = (Agcmpnode_t *) aggetrec(cmpnode, Descriptor_id, FALSE);
-
- subg = noderec->subg;
- root = agroot(g);
-
- /* make sure caller hasn't put a node "inside itself" */
- if ((n = agsubnode(subg, cmpnode, FALSE)))
- agdelnode(n);
-
- /* remap edges by splicing and saving previous endpt */
- for (n = agfstnode(subg); n; n = agnxtnode(n)) {
- rootn = agsubnode(root, n, FALSE);
- for (e = agfstedge(rootn); e; e = f) {
- f = agnxtedge(e, rootn);
- if (agsubedge(subg, e, FALSE))
- continue; /* an internal edge */
- opp = AGOPP(e);
- stackpush(save_stack_of(e, rootn), rootn, cmpnode);
- agsplice(opp, cmpnode);
- }
- }
-
- /* hide nodes by deleting from the parent set. what if they also
- belong to a sibling subg? weird. possible bug. */
- for (n = agfstnode(subg); n; n = nn) {
- nn = agnxtnode(n);
- delete_outside_subg(root, n, subg);
- }
-
- /* hide subgraph is easy */
- agdelsubg(agparent(subg), subg);
-
- noderec->collapsed = TRUE;
- g->desc.has_cmpnd = TRUE;
- return SUCCESS;
-}
-
-/* utility function for agexpose */
-static void insert_outside_subg(Agraph_t * g, Agnode_t * node,
- Agraph_t * subg)
-{
- Agraph_t *s, **subglist;
- Agnode_t *n;
- Agcmpgraph_t *graphrec;
-
- if ((g != subg)
- && ((n = agsubnode(g, (Agnode_t *) node, FALSE)) == NILnode)) {
- graphrec = (Agcmpgraph_t *) aggetrec(g, Descriptor_id, FALSE);
- if (graphrec
- &&
- ((n = (Agnode_t *) dtsearch(graphrec->hidden_node_set, node))))
- dtinsert(g->n_dict, n);
-
- subglist = agsubglist(g);
- while ((s = *subglist++))
- delete_outside_subg(s, node, subg);
- }
-}
-
-int agexpose(Agnode_t * cmpnode)
-{
- Agcmpnode_t *noderec;
- Agcmpedge_t *edgerec;
- Agraph_t *g, *subg, *root;
- Agnode_t *n, *rootcmp;
- Agedge_t *e, *f;
- save_stack_t *stk;
- save_e_t sav;
- int i;
-
- g = agraphof(cmpnode);
-
- /* skip if this is not a collapsed subgraph */
- noderec = (Agcmpnode_t *) aggetrec(cmpnode, Descriptor_id, FALSE);
- if ((noderec == NIL(Agcmpnode_t *) || NOT(noderec->collapsed)))
- return FAILURE;
-
- /* undo aghide (above) in reverse order. first, expose subgraph */
- subg = noderec->subg;
- agsubgrec_insert(agsubgrec(agparent(subg)), subg);
-
- /* re-insert nodes */
- for (n = agfstnode(subg); n; n = agnxtnode(n))
- insert_outside_subg(g, n, subg);
-
- /* re-splice the affected edges */
- root = agroot(g);
- rootcmp = agsubnode(root, cmpnode, FALSE);
- for (e = agfstedge(rootcmp); e; e = f) {
- f = agnxtedge(e, rootcmp);
- if ((edgerec = (Agcmpedge_t *) aggetrec(e, Descriptor_id, FALSE))) {
- /* anything interesting on either stack? */
- for (i = 0; i < 2; i++) {
- stk = &(edgerec->stack[i]);
- sav = stacktop(stk);
- if (sav.to && (AGID(sav.to) == AGID(cmpnode))) {
- if (e->node != sav.to)
- e = AGOPP(e);
- agsplice(e, sav.from);
- stackpop(stk);
- continue;
- }
- }
- }
- }
- noderec->collapsed = FALSE;
- return SUCCESS;
-}
-
-Agraph_t *agcmpgraph_of(Agnode_t * n)
-{
- Agcmpnode_t *noderec;
- noderec = (Agcmpnode_t *) aggetrec(n, Descriptor_id, FALSE);
- if (noderec && NOT(noderec->collapsed))
- return noderec->subg;
- else
- return NILgraph;
-}
-
-Agnode_t *agcmpnode_of(Agraph_t * g)
-{
- Agcmpgraph_t *graphrec;
- graphrec = (Agcmpgraph_t *) aggetrec(g, Descriptor_id, FALSE);
- if (graphrec)
- return graphrec->node;
- else
- return NILnode;
-}
-
-Agnode_t *agfindhidden(Agraph_t * g, char *name)
-{
- Agcmpgraph_t *graphrec;
- Agnode_t key;
-
- graphrec = (Agcmpgraph_t *) aggetrec(g, Descriptor_id, FALSE);
- if (graphrec) {
- key.name = name;
- return (Agnode_t *) dtsearch(graphrec->hidden_node_set, &key);
- } else
- return NILnode;
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include <assert.h>
-#include <signal.h>
-#include <stdio.h>
-#include "agraph.h"
-
-#define NILgraph NIL(Agraph_t*)
-#define NILnode NIL(Agnode_t*)
-#define NILedge NIL(Agedge_t*)
-#define NILsym NIL(Agsym_t*)
-#define NILstr NIL(char*)
-
-void main(int argc, char **argv)
-{
- Agraph_t *g;
- Agnode_t *n;
- Agedge_t *e;
-
- while (g = agread(stdin, NIL(Agdisc_t *))) {
- fprintf(stderr, "nodes %d edges %d\n", agnnodes(g), agnedges(g));
- for (n = agfstnode(g); n; n = agnxtnode(n)) {
- if (agdegree(n, TRUE, TRUE) == 0)
- printf("u . \"%s\" {}\n", agnameof(n));
- else {
- for (e = agfstout(n); e; e = agnxtout(e)) {
- printf("u .> \"%s\" {} e%x {} ", agnameof(agtail(e)),
- e);
- printf("\"%s\" {}\n", agnameof(aghead(e)));
- }
- }
- }
- }
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-#define IN_SET FALSE
-#define OUT_SET TRUE
-#define ID_ORDER TRUE
-#define SEQ_ORDER FALSE
-
-static Agtag_t Tag; /* to silence warnings about initialization */
-
-Agedge_t *agfstout(Agnode_t * n)
-{
- Agraph_t *g;
- Agedge_t *e = NILedge;
-
- g = agraphof(n);
- if (agisflattened(g))
- e = AGFSTOUT(n);
- else {
- dtrestore(g->e_seq, &(n->out->base.seq_link));
- e = (Agedge_t *) dtfirst(g->e_seq);
- n->out = (Agedge_t *) dtextract(g->e_seq);
- }
- return e;
-}
-
-Agedge_t *agnxtout(Agedge_t * e)
-{
- Agraph_t *g;
- Agnode_t *n;
- Agedge_t *f;
-
- g = agraphof(e);
- if (agisflattened(g))
- f = AGNXTE(e);
- else {
- n = AGTAIL(e);
- dtrestore(g->e_seq, &(n->out->base.seq_link));
- f = (Agedge_t *) dtnext(g->e_seq, e);
- n->out = (Agedge_t *) dtextract(g->e_seq);
- }
- return f;
-}
-
-Agedge_t *agfstin(Agnode_t * n)
-{
- Agraph_t *g;
- Agedge_t *e = NILedge;
-
- g = agraphof(n);
- if (agisflattened(g))
- e = AGFSTIN(n);
- else {
- dtrestore(g->e_seq, &(n->in->base.seq_link));
- e = (Agedge_t *) dtfirst(g->e_seq);
- n->in = (Agedge_t *) dtextract(g->e_seq);
- }
- return e;
-}
-
-Agedge_t *agnxtin(Agedge_t * e)
-{
- Agraph_t *g;
- Agnode_t *n;
- Agedge_t *f;
-
- g = agraphof(e);
- if (agisflattened(g))
- f = AGNXTE(e);
- else {
- n = AGHEAD(e);
- dtrestore(g->e_seq, &(n->in->base.seq_link));
- f = (Agedge_t *) dtnext(g->e_seq, e);
- n->in = (Agedge_t *) dtextract(g->e_seq);
- }
- return f;
-}
-
-Agedge_t *agfstedge(Agnode_t * n)
-{
- Agedge_t *rv;
- rv = agfstout(n);
- if (rv == NILedge)
- rv = agfstin(n);
- return rv;
-}
-
-Agedge_t *agnxtedge(Agedge_t * e, Agnode_t * n)
-{
- Agedge_t *rv;
- if (AGID(n) == AGID(agtail(e))) {
- rv = agnxtout(e);
- if (rv == NILedge)
- rv = agfstin(n);
- } else
- rv = agnxtin(e);
- return rv;
-}
-
-static Agedge_t *agfindedge(Agnode_t * t, Agnode_t * h, Agtag_t key)
-{
- Agraph_t *g;
- Agedge_t *e, template;
-
- assert(agraphof(t) == agraphof(h));
-
- g = agraphof(t);
- template.base.tag = key; /* guess that fan-in < fan-out */
- template.node = t;
- if (t != h) { /* guess that fan-in < fan-out */
- dtrestore(g->e_id, h->inid);
- e = (Agedge_t *) dtsearch(g->e_id, &template);
- h->inid = dtextract(g->e_id);
- } else {
- dtrestore(g->e_id, t->outid);
- e = (Agedge_t *) dtsearch(g->e_id, &template);
- t->outid = dtextract(g->e_id);
- }
- return e;
-}
-
-static Agedge_t *agfindedge_by_id(Agnode_t * t, Agnode_t * h,
- unsigned long id)
-{
- Agtag_t tag;
-
- assert(agraphof(t) == agraphof(h));
- tag = Tag;
- tag.objtype = AGEDGE;
- tag.id = id;
- return agfindedge(t, h, tag);
-}
-
-void agedgesetop(Agraph_t * g, Agedge_t * e, int ins)
-{
- union {
- Dtlink_t **dtlink;
- Agedge_t **agedge;
- } seq_set;
- Dtlink_t **id_set;
- Agnode_t *n; /* node where <e> is referenced */
-
- if (AGTYPE(e) == AGOUTEDGE) {
- n = AGOUT2IN(e)->node;
- seq_set.agedge = &(n->out);
- id_set = &(n->outid);
- } else {
- n = AGIN2OUT(e)->node;
- seq_set.agedge = &(n->in);
- id_set = &(n->inid);
- }
-
- dtrestore(g->e_seq, *seq_set.dtlink);
- if (ins)
- dtinsert(g->e_seq, e);
- else
- dtdelete(g->e_seq, e);
- *seq_set.dtlink = dtextract(g->e_seq);
-
- dtrestore(g->e_id, *id_set);
- if (ins)
- dtinsert(g->e_id, e);
- else
- dtdelete(g->e_id, e);
- *id_set = dtextract(g->e_id);
-}
-
-/* creates new edge pair and returns outedge */
-static Agedgepair_t *newedgepair(Agraph_t * g, Agnode_t * t, Agnode_t * h,
- unsigned long id, unsigned long seq)
-{
- Agedgepair_t *e2;
- Agedge_t *in, *out;
-
- e2 = (Agedgepair_t *) agalloc(g, sizeof(Agedgepair_t));
- in = &(e2->in);
- out = &(e2->out);
- AGTYPE(in) = AGINEDGE;
- AGTYPE(out) = AGOUTEDGE;
- AGID(in) = AGID(out) = id;
- AGSEQ(in) = AGSEQ(out) = seq;
- in->node = t;
- out->node = h;
- agedgesetop(g, out, TRUE);
- if (t != h)
- agedgesetop(g, in, TRUE);
- return e2;
-}
-
-static Agedge_t *mklocaledge(Agraph_t * g, Agnode_t * arg_t,
- Agnode_t * arg_h, unsigned long id,
- int *isnew)
-{
- Agedge_t *e, *epar;
- Agraph_t *par;
- Agnode_t *t, *h;
- Agtag_t key;
- Agedgepair_t *e2;
-
- agnotflat(g);
-
- t = agsubnode(g, arg_t, TRUE);
- h = agsubnode(g, arg_h, TRUE);
- /* protect against multi-edges */
- key = Tag;
- if (agisstrict(g))
- key.objtype = 0;
- else
- key.objtype = AGEDGE;
- key.id = id;
- if ((e = agfindedge(t, h, key)))
- return e;
-
- if ((par = agparent(g))) {
- epar = mklocaledge(par, t, h, id, isnew);
- } else {
- epar = NILedge;
- *isnew = TRUE;
- }
-
- e2 = newedgepair(g, t, h, id,
- epar ? AGSEQ(epar) : agnextseq(g, AGEDGE));
- e = &(e2->out);
- if (epar)
- AGDATA(&(e2->in)) = AGDATA(&(e2->out)) = AGDATA(epar);
- else {
- if (g->desc.has_attrs)
- (void) agrealbindrec(e, AgDataRecName, sizeof(Agattr_t), FALSE,
- TRUE);
- /* edgeattr_init and method_init will be called later */
- }
- return e;
-}
-
-static Agedge_t *localedge(Agraph_t * g, Agnode_t * arg_t,
- Agnode_t * arg_h, unsigned long id)
-{
- int isnew = FALSE;
- Agedge_t *e;
- e = mklocaledge(g, arg_t, arg_h, id, &isnew);
- if (isnew) {
- if (g->desc.has_attrs)
- agedgeattr_init(e, TRUE);
- agmethod_init(g, e);
- }
- return e;
-}
-
-static int ok_to_make_edge(Agnode_t * t, Agnode_t * h)
-{
- Agraph_t *g;
- Agtag_t key;
-
- g = agraphof(t);
-
- /* protect against endpoints in different graphs */
- g = agraphof(t);
- if (g != agraphof(h))
- return FALSE;
-
- /* protect against self, multi-edges in strict graphs */
- if (agisstrict(g)) {
- if (AGID(t) == AGID(h))
- return FALSE;
- key = Tag;
- key.objtype = 0; /* wild card */
- if (agfindedge(t, h, key))
- return FALSE;
- }
- return TRUE;
-}
-
-Agedge_t *agidedge(Agnode_t * t, Agnode_t * h, unsigned long id, int cflag)
-{
- Agraph_t *g, *root;
- Agnode_t *tr, *hr;
- Agedge_t *e;
-
- if ((g = agraphof(t)) != agraphof(h))
- return NILedge;
- e = agfindedge_by_id(t, h, id);
- if ((e == NILedge) && agisundirected(g))
- e = agfindedge_by_id(h, t, id);
- if ((e == NILedge) && cflag && ok_to_make_edge(t, h)) {
- root = agroot(g);
- if (((g != root) && ((tr = agsubnode(root, t, FALSE))) /* old */
- &&((hr = agsubnode(root, h, FALSE)))
- && agfindedge_by_id(tr, hr, id))
- || agallocid(g, AGEDGE, id)) /* new */
- e = localedge(g, t, h, id);
- }
- return e;
-}
-
-Agedge_t *agedge(Agnode_t * t, Agnode_t * h, char *name, int cflag)
-{
- Agraph_t *g;
- Agedge_t *e;
- unsigned long id;
- int have_id;
-
- if ((g = agraphof(t)) != agraphof(h))
- return NILedge;
- have_id = agmapnametoid(g, AGEDGE, name, &id, FALSE);
- if (have_id || ((name == NILstr) && (NOT(cflag) || agisstrict(g)))) {
- /* probe for pre-existing edge */
- Agtag_t key;
- key = Tag;
- if (have_id) {
- key.id = id;
- key.objtype = AGEDGE;
- } else {
- key.id = key.objtype = 0;
- }
-
- /* might already exist locally */
- e = agfindedge(t, h, key);
- if ((e == NILedge) && agisundirected(g))
- e = agfindedge(h, t, key);
- if (e)
- return e;
- }
-
- if (cflag && ok_to_make_edge(t, h)
- && agmapnametoid(g, AGEDGE, name, &id, TRUE)) /* reserve id */
- e = localedge(g, t, h, id);
- else
- e = NILedge;
- return e;
-}
-
-void agdeledgepair(Agedge_t * e, void *ignored)
-{
- Agraph_t *g;
- Agedge_t *in, *out;
- Agnode_t *t, *h;
-
- NOTUSED(ignored);
- g = agraphof(e);
- agnotflat(g);
- if (AGTYPE(e) == AGINEDGE) {
- in = e;
- out = AGIN2OUT(e);
- } else {
- out = e;
- in = AGOUT2IN(e);
- }
- t = in->node;
- h = out->node;
- agedgesetop(g, out, FALSE);
- if (t != h)
- agedgesetop(g, in, FALSE);
- agfree(g, out);
- for (e = agfstin(h); e; e = agnxtin(e))
- assert(e != in);
- for (e = agfstout(t); e; e = agnxtout(e))
- assert(e != out);
-}
-
-int agdeledge(Agedge_t * e)
-{
- Agraph_t *g;
-
- g = agraphof(e);
- e = AGMKOUT(e);
-
- if (agfindedge(agtail(e), aghead(e), AGTAG(e)) == NILedge)
- return FAILURE;
-
- if (agisarootobj(e)) {
- if (g->desc.has_attrs)
- agedgeattr_delete(e);
- agmethod_delete(g, e);
- agrecclose((Agobj_t *) e);
- agfreeid(g, AGEDGE, AGID(e));
- }
- return agapply(g, (Agobj_t *) e, (agobjfn_t) agdeledgepair, NILedge,
- FALSE);
-}
-
-
-Agedge_t *agsubedge(Agraph_t * g, Agedge_t * arg_e, int cflag)
-{
- Agnode_t *t, *h;
- Agedge_t *e;
-
- if (agraphof(arg_e) == g)
- return arg_e;
-
- agnotflat(g);
- t = agsubnode(g, AGTAIL(arg_e), cflag);
- h = agsubnode(g, AGHEAD(arg_e), cflag);
- if ((t == NILnode) || (h == NILnode))
- e = NILedge;
- else {
- e = agfindedge(t, h, AGTAG(arg_e));
- if (cflag && (e == NILedge)) {
- e = localedge(g, t, h, AGID(arg_e));
- }
- }
- if (e && (AGTYPE(e) != AGTYPE(arg_e)))
- e = AGOPP(e);
- return e;
-}
-
-
-/* edge comparison. OBJTYPE(e) == 0 means ID is a wildcard. */
-int agedgecmpf(Dict_t * d, void *arg_e0, void *arg_e1, Dtdisc_t * disc)
-{
- int rv;
- Agedge_t *e0, *e1;
-
- NOTUSED(d);
- e0 = arg_e0;
- e1 = arg_e1;
- NOTUSED(disc);
- rv = AGID(e0->node) - AGID(e1->node);
- if (rv == 0) { /* same node */
- if ((AGTYPE(e0) == 0) || (AGTYPE(e1) == 0))
- rv = 0;
- else
- rv = AGID(e0) - AGID(e1);
- }
- return rv;
-}
-
- /* discipline for edges that compares endpoints + ID */
-Dtdisc_t Ag_edge_disc = {
- 0, /* obj is passed as key */
- 0, /* key size (ignored) */
- offsetof(Agedge_t, base.id_link), /* link offset */
- NIL(Dtmake_f),
- NIL(Dtfree_f),
- agedgecmpf,
- NIL(Dthash_f)
-};
-
-/* debug functions */
-#ifdef agtail
-#undef agtail
-#endif
-Agnode_t *agtail(Agedge_t * e)
-{
- return AGTAIL(e);
-}
-
-#ifdef aghead
-#undef aghead
-#endif
-Agnode_t *aghead(Agedge_t * e)
-{
- return AGHEAD(e);
-}
-
-#ifdef agopp
-#undef agopp
-#endif
-Agedge_t *agopp(Agedge_t * e)
-{
- return AGOPP(e);
-}
-
-#ifdef NOTDEF
- /* could be useful if we write relabel_edge */
-static Agedge_t *agfindedge_by_name(Agnode_t * t, Agnode_t * h, char *name)
-{
- unsigned long id;
-
- if (agmapnametoid(agraphof(t), AGEDGE, name, &id, FALSE))
- return agfindedge_by_id(t, h, id);
- else
- return NILedge;
-}
-#endif
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-void agflatten_elist(Dict_t * d, Dtlink_t ** lptr)
-{
- dtrestore(d, *lptr);
- (void) dtflatten(d);
- *lptr = dtextract(d);
-}
-
-void agflatten_edges(Agraph_t * g, Agnode_t * n)
-{
-
- union {
- Dtlink_t **dtlink;
- Agedge_t **agedge;
- } out, in;
-
- out.agedge = & (n->out);
- in.agedge = & (n->in);
- agflatten_elist(g->e_seq, out.dtlink);
- agflatten_elist(g->e_seq, in.dtlink);
-
-}
-
-void agflatten(Agraph_t * g, int flag)
-{
- Agnode_t *n;
-
- if (flag) {
- if (g->desc.flatlock == FALSE) {
- dtflatten(g->n_seq);
- g->desc.flatlock = TRUE;
- for (n = agfstnode(g); n; n = agnxtnode(n))
- agflatten_edges(g, n);
- }
- } else {
- if (g->desc.flatlock) {
- g->desc.flatlock = FALSE;
- }
- }
-}
-
-void agnotflat(Agraph_t * g)
-{
- if (g->desc.flatlock)
- agerror(AGERROR_FLAT, "");
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-%{
-
-#include <stdio.h> /* SAFE */
-#include "aghdr.h" /* SAFE */
-
-#ifdef _WIN32
-#define gettxt(a,b) (b)
-#endif
-
-static char Key[] = "key";
-
-typedef union s { /* possible items in generic list */
- Agnode_t *n;
- Agraph_t *subg;
- Agedge_t *e;
- Agsym_t *asym; /* bound attribute */
- char *name; /* unbound attribute */
- struct item_s *list; /* list-of-lists (for edgestmt) */
-} val_t;
-
-typedef struct item_s { /* generic list */
- int tag; /* T_node, T_subgraph, T_edge, T_attr */
- val_t u; /* primary element */
- char *str; /* secondary value - port or attr value */
- struct item_s *next;
-} item;
-
-typedef struct list_s { /* maintain head and tail ptrs for fast append */
- item *first;
- item *last;
-} list_t;
-
-/* functions */
-static void appendnode(char *name, char *port, char *sport);
-static void attrstmt(int tkind, char *macroname);
-static void startgraph(char *name, int directed, int strict);
-static void bufferedges(void);
-static void newedge(Agnode_t *t, char *tport, Agnode_t *h, char *hport, char *key);
-static void edgerhs(Agnode_t *n, char *tport, item *hlist, char *key);
-static void appendattr(char *name, char *value);
-static void bindattrs(int kind);
-static void applyattrs(void *obj);
-static void endgraph(void);
-static void endnode(void);
-static void endedge(void);
-static char* concat(char*, char*);
-static char* concatPort(char*, char*);
-
-static void opensubg(char *name);
-static void closesubg(void);
-
-/* global */
-static Agraph_t *G;
-
-%}
-
-%union {
- int i;
- char *str;
- struct Agnode_s *n;
-}
-
-%token <i> T_graph T_node T_edge T_digraph T_subgraph T_strict T_edgeop
- /* T_list, T_attr are internal tags, not really tokens */
-%token T_list T_attr
-%token <str> T_atom T_qatom
-
-%type <i> optstrict graphtype rcompound attrtype
-%type <str> optsubghdr optgraphname optmacroname atom qatom
-
-
-%%
-
-graph : hdr body {endgraph();}
- | error {if (G) {agclose(G); G = Ag_G_global = NIL(Agraph_t*);}}
- | /* empty */
- ;
-
-body : '{' optstmtlist '}' ;
-
-hdr : optstrict graphtype optgraphname {startgraph($3,$2,$1);}
- ;
-
-optgraphname: atom {$$=$1;} | /* empty */ {$$=0;} ;
-
-optstrict : T_strict {$$=1;} | /* empty */ {$$=0;} ;
-
-graphtype : T_graph {$$ = 0;} | T_digraph {$$ = 1;} ;
-
-optstmtlist : stmtlist | /* empty */ ;
-
-stmtlist : stmtlist stmt | stmt ;
-
-optsemi : ';' | ;
-
-stmt : attrstmt optsemi
- | compound optsemi
- ;
-
-compound : simple rcompound optattr
- {if ($2) endedge(); else endnode();}
- ;
-
-simple : nodelist | subgraph ;
-
-rcompound : T_edgeop {bufferedges();} simple rcompound {$$ = 1;}
- | /* empty */ {$$ = 0;}
- ;
-
-
-nodelist : node | nodelist ',' node ;
-
-node : atom {appendnode($1,NIL(char*),NIL(char*));}
- | atom ':' atom {appendnode($1,$3,NIL(char*));}
- | atom ':' atom ':' atom {appendnode($1,$3,$5);}
- ;
-
-attrstmt : attrtype optmacroname attrlist {attrstmt($1,$2);}
- | graphattrdefs {attrstmt(T_graph,NIL(char*));}
- ;
-
-attrtype : T_graph {$$ = T_graph;}
- | T_node {$$ = T_node;}
- | T_edge {$$ = T_edge;}
- ;
-
-optmacroname : atom '=' {$$ = $1;}
- | /* empty */ {$$ = NIL(char*); }
- ;
-
-optattr : attrlist | /* empty */ ;
-
-attrlist : optattr '[' optattrdefs ']' ;
-
-optattrdefs : optattrdefs attrdefs
- | /* empty */ ;
-
-attrdefs : attritem optseparator
- ;
-
-attritem : attrassignment | attrmacro ;
-
-attrassignment : atom '=' atom {appendattr($1,$3);}
- ;
-
-attrmacro : '@' atom {appendattr($2,NIL(char*));} /* not yet impl */
- ;
-
-graphattrdefs : attrassignment
- ;
-
-subgraph : optsubghdr {opensubg($1);} body {closesubg();}
- ;
-
-optsubghdr : T_subgraph atom {$$=$2;}
- | T_subgraph {$$=NIL(char*);}
- | /* empty */ {$$=NIL(char*);}
- ;
-
-optseparator : ';' | ',' | /*empty*/ ;
-
-atom : T_atom {$$ = $1;}
- | qatom {$$ = $1;}
- ;
-
-qatom : T_qatom {$$ = $1;}
- | qatom '+' T_qatom {$$ = concat($1,$3);}
- ;
-%%
-
-#define NILitem NIL(item*)
-
-/* globals */
-static Agraph_t *Subgraph; /* most recent subgraph that was opened */
-static Agdisc_t *Disc; /* discipline passed to agread or agconcat */
-static list_t Nodelist,Edgelist,Attrlist;
-
-static item *newitem(int tag, void *p0, char *p1)
-{
- item *rv = agalloc(G,sizeof(item));
- rv->tag = tag; rv->u.name = (char*)p0; rv->str = p1;
- return rv;
-}
-
-static item *cons_node(Agnode_t *n, char *port)
- { return newitem(T_node,n,port); }
-
-static item *cons_attr(char *name, char *value)
- { return newitem(T_atom,name,value); }
-
-static item *cons_list(item *list)
- { return newitem(T_list,list,NIL(char*)); }
-
-static item *cons_subg(Agraph_t *subg)
- { return newitem(T_subgraph,subg,NIL(char*)); }
-
-#ifdef NOTDEF
-static item *cons_edge(Agedge_t *e)
- { return newitem(T_edge,e,NIL(char*)); }
-#endif
-
-static void delete_items(item *ilist)
-{
- item *p,*pn;
-
- for (p = ilist; p; p = pn) {
- pn = p->next;
- switch(p->tag) {
- case T_list: delete_items(p->u.list); break;
- case T_atom: case T_attr: agstrfree(G,p->str); break;
- }
- agfree(G,p);
- }
-}
-
-static void deletelist(list_t *list)
-{
- delete_items(list->first);
- list->first = list->last = NILitem;
-}
-
-#ifdef NOTDEF
-static void listins(list_t *list, item *v)
-{
- v->next = list->first;
- list->first = v;
- if (list->last == NILitem) list->last = v;
-}
-#endif
-
-static void listapp(list_t *list, item *v)
-{
- if (list->last) list->last->next = v;
- list->last = v;
- if (list->first == NILitem) list->first = v;
-}
-
-
-/* attrs */
-static void appendattr(char *name, char *value)
-{
- item *v;
-
- assert(value != NIL(char*));
- v = cons_attr(name,value);
- listapp(&Attrlist,v);
-}
-
-static void bindattrs(int kind)
-{
- item *aptr;
- char *name;
-
- for (aptr = Attrlist.first; aptr; aptr = aptr->next) {
- assert(aptr->tag == T_atom); /* signifies unbound attr */
- name = aptr->u.name;
- if ((kind == AGEDGE) && streq(name,Key)) continue;
- if ((aptr->u.asym = agattr(G,kind,name,NIL(char*))) == NILsym)
- aptr->u.asym = agattr(G,kind,name,"");
- aptr->tag = T_attr; /* signifies bound attr */
- agstrfree(G,name);
- }
-}
-
-static void applyattrs(void *obj)
-{
- item *aptr;
-
- for (aptr = Attrlist.first; aptr; aptr = aptr->next) {
- if (aptr->tag == T_attr) {
- if (aptr->u.asym) {
- agxset(obj,aptr->u.asym,aptr->str);
- }
- }
- else {
- assert(AGTYPE(obj) == AGEDGE);
- assert(aptr->tag == T_atom);
- assert(streq(aptr->u.name,Key));
- }
- }
-}
-
-static void nomacros(void)
-{
- agerror(AGERROR_UNIMPL,"attribute macros");
-}
-
-static void attrstmt(int tkind, char *macroname)
-{
- item *aptr;
- int kind;
-
- /* creating a macro def */
- if (macroname) nomacros();
- /* invoking a macro def */
- for (aptr = Attrlist.first; aptr; aptr = aptr->next)
- if (aptr->str == NIL(char*)) nomacros();
-
- switch(tkind) {
- case T_graph: kind = AGRAPH; break;
- case T_node: kind = AGNODE; break;
- case T_edge: kind = AGEDGE; break;
- default : abort();
- }
- bindattrs(kind); /* set up defaults for new attributes */
- for (aptr = Attrlist.first; aptr; aptr = aptr->next)
- agattr(G,kind,aptr->u.asym->name,aptr->str);
- deletelist(&Attrlist);
-}
-
-/* nodes */
-
-static void appendnode(char *name, char *port, char *sport)
-{
- item *elt;
-
- if (sport) {
- port = concatPort (port, sport);
- }
- elt = cons_node(agnode(G,name,TRUE),port);
- listapp(&Nodelist,elt);
- agstrfree(G,name);
-}
-
- /* apply current optional attrs to Nodelist and clean up lists */
-static void endnode()
-{
- item *ptr;
-
- bindattrs(AGNODE);
- for (ptr = Nodelist.first; ptr; ptr = ptr->next)
- applyattrs(ptr->u.n);
- deletelist(&Nodelist);
- deletelist(&Attrlist);
-}
-
-/* edges - store up node/subg lists until optional edge key can be seen */
-
-static void bufferedges()
-{
- item *v;
-
- if (Nodelist.first) {
- v = cons_list(Nodelist.first);
- Nodelist.first = Nodelist.last = NILitem;
- }
- else {v = cons_subg(Subgraph); Subgraph = NIL(Agraph_t*);}
- listapp(&Edgelist,v);
-}
-
-static void endedge(void)
-{
- char *key;
- item *aptr,*tptr,*p;
-
- Agnode_t *t;
- Agraph_t *subg;
-
- bufferedges(); /* pick up the terminal nodelist or subg */
- bindattrs(AGEDGE);
-
- /* look for "key" pseudo-attribute */
- key = NIL(char*);
- for (aptr = Attrlist.first; aptr; aptr = aptr->next) {
- if ((aptr->tag == T_atom) && streq(aptr->u.name,Key))
- key = aptr->str;
- }
-
- /* can make edges with node lists or subgraphs */
- for (p = Edgelist.first; p->next; p = p->next) {
- if (p->tag == T_subgraph) {
- subg = p->u.subg;
- for (t = agfstnode(subg); t; t = agnxtnode(t))
- edgerhs(agsubnode(G,t,FALSE),NIL(char*),p->next,key);
- }
- else {
- for (tptr = p->u.list; tptr; tptr = tptr->next)
- edgerhs(tptr->u.n,tptr->str,p->next,key);
- }
- }
- deletelist(&Edgelist);
- deletelist(&Attrlist);
-}
-
-/* concat:
- */
-static char*
-concat (char* s1, char* s2)
-{
- char* s;
- char buf[BUFSIZ];
- char* sym;
- int len = strlen(s1) + strlen(s2) + 1;
-
- if (len <= BUFSIZ) sym = buf;
- else sym = (char*)malloc(len);
- strcpy(sym,s1);
- strcat(sym,s2);
- s = agstrdup (G,sym);
- agstrfree (G,s1);
- agstrfree (G,s2);
- if (sym != buf) free (sym);
- return s;
-}
-
-/* concatPort:
- */
-static char*
-concatPort (char* s1, char* s2)
-{
- char* s;
- char buf[BUFSIZ];
- char* sym;
- int len = strlen(s1) + strlen(s2) + 2; /* one more for ':' */
-
- if (len <= BUFSIZ) sym = buf;
- else sym = (char*)malloc(len);
- sprintf (sym, "%s:%s", s1, s2);
- s = agstrdup (G,sym);
- agstrfree (G,s1);
- agstrfree (G,s2);
- if (sym != buf) free (sym);
- return s;
-}
-
-
-static void edgerhs(Agnode_t *tail, char *tport, item *hlist, char *key)
-{
- Agnode_t *head;
- Agraph_t *subg;
- item *hptr;
-
- if (hlist->tag == T_subgraph) {
- subg = hlist->u.subg;
- for (head = agfstnode(subg); head; head = agnxtnode(head))
- newedge(tail,tport,agsubnode(G,head,FALSE),NIL(char*),key);
- }
- else {
- for (hptr = hlist->u.list; hptr; hptr = hptr->next)
- newedge(tail,tport,agsubnode(G,hptr->u.n,FALSE),hptr->str,key);
- }
-}
-
-static void mkport(Agedge_t *e, char *name, char *val)
-{
- Agsym_t *attr;
- if (val) {
- if ((attr = agattr(G,AGEDGE,name,NIL(char*))) == NILsym)
- attr = agattr(G,AGEDGE,name,"");
- agxset(e,attr,val);
- }
-}
-
-static void newedge(Agnode_t *t, char *tport, Agnode_t *h, char *hport, char *key)
-{
- Agedge_t *e;
-
- e = agedge(t,h,key,TRUE);
- if (e) { /* can fail if graph is strict and t==h */
- char *tp = tport;
- char *hp = hport;
- if ((agtail(e) != aghead(e)) && (aghead(e) == t)) {
- /* could happen with an undirected edge */
- char *temp;
- temp = tp; tp = hp; hp = temp;
- }
- mkport(e,TAIL_ID,tp);
- mkport(e,HEAD_ID,hp);
- applyattrs(e);
- }
-}
-
-/* graphs and subgraphs */
-
-
-static void startgraph(char *name, int directed, int strict)
-{
- static Agdesc_t req; /* get rid of warnings */
-
- if (G == NILgraph) {
- req.directed = directed;
- req.strict = strict;
- req.flatlock = FALSE;
- req.maingraph = TRUE;
- Ag_G_global = G = agopen(name,req,Disc);
- }
- else {
- Ag_G_global = G;
- }
- agstrfree(NIL(Agraph_t*),name);
-}
-
-static void endgraph()
-{
- aglexeof();
- aginternalmapclearlocalnames(G);
-}
-
-static void opensubg(char *name)
-{
- G = agsubg(G,name,TRUE);
- agstrfree(G,name);
-}
-
-static void closesubg()
-{
- Subgraph = G;
- if ((G = agparent(G)) == NIL(Agraph_t*))
- yyerror("libgraph: parser lost root graph\n");
-}
-
-extern FILE *yyin;
-Agraph_t *agconcat(Agraph_t *g, void *chan, Agdisc_t *disc)
-{
- yyin = chan;
- G = g;
- Ag_G_global = NILgraph;
- Disc = (disc? disc : &AgDefaultDisc);
- aglexinit(Disc, chan);
- yyparse();
- return Ag_G_global;
-}
-
-Agraph_t *agread(void *fp, Agdisc_t *disc) {return agconcat(NILgraph,fp,disc); }
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#define EXTERN
-#include "aghdr.h"
-
-const char AgraphVersion[] = VERSION;
-
-/*
- * this code sets up the resource management discipline
- * and returns a new main graph struct.
- */
-static Agclos_t *agclos(Agdisc_t * proto)
-{
- Agmemdisc_t *memdisc;
- void *memclosure;
- Agclos_t *rv;
-
- /* establish an allocation arena */
- memdisc = ((proto && proto->mem) ? proto->mem : &AgMemDisc);
- memclosure = memdisc->open();
- rv = memdisc->alloc(memclosure, sizeof(Agclos_t));
- rv->disc.mem = memdisc;
- rv->state.mem = memclosure;
- rv->disc.id = ((proto && proto->id) ? proto->id : &AgIdDisc);
- rv->disc.io = ((proto && proto->io) ? proto->io : &AgIoDisc);
- rv->callbacks_enabled = TRUE;
- return rv;
-}
-
-/*
- * Open a new main graph with the given descriptor (directed, strict, etc.)
- */
-Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * arg_disc)
-{
- Agraph_t *g;
- Agclos_t *clos;
- unsigned long gid;
-
- clos = agclos(arg_disc);
- g = clos->disc.mem->alloc(clos->state.mem, sizeof(Agraph_t));
- AGTYPE(g) = AGRAPH;
- g->clos = clos;
- g->desc = desc;
- g->desc.maingraph = TRUE;
- g->root = g;
- g->clos->state.id = g->clos->disc.id->open(g);
- if (agmapnametoid(g, AGRAPH, name, &gid, TRUE))
- AGID(g) = gid;
- /* else AGID(g) = 0 because we have no alternatives */
- return agopen1(g);
-}
-
-/*
- * initialize dictionaries, set seq, invoke init method of new graph
- */
-Agraph_t *agopen1(Agraph_t * g)
-{
- Agraph_t *par;
-
- g->n_seq = agdtopen(g, &Ag_obj_seq_disc, Dttree);
- g->n_id = agdtopen(g, &Ag_obj_id_disc, Dttree);
- g->e_seq = agdtopen(g, &Ag_obj_seq_disc, Dttree);
- g->e_id = agdtopen(g, &Ag_edge_disc, Dttree);
- g->g_dict = agdtopen(g, &Ag_obj_id_disc, Dttree);
-
- par = agparent(g);
- if (par) {
- AGSEQ(g) = agnextseq(par, AGRAPH);
- dtinsert(par->g_dict, g);
- } /* else AGSEQ=0 */
- if (g->desc.has_attrs)
- agraphattr_init(g, FALSE);
- agmethod_init(g, g);
- return g;
-}
-
-/*
- * Close a graph or subgraph, freeing its storage.
- */
-int agclose(Agraph_t * g)
-{
- Agraph_t *subg, *next_subg, *par;
- Agnode_t *n, *next_n;
-
- agflatten(g, FALSE);
- par = agparent(g);
-
- if ((par == NILgraph) && (AGDISC(g, mem)->close)) {
- /* free entire heap */
- agmethod_delete(g, g); /* invoke user callbacks */
- agfreeid(g, AGRAPH, AGID(g));
- AGDISC(g, mem)->close(AGCLOS(g, mem)); /* whoosh */
- return SUCCESS;
- }
-
- for (subg = agfstsubg(g); subg; subg = next_subg) {
- next_subg = agnxtsubg(subg);
- agclose(subg);
- }
-
- for (n = agfstnode(g); n; n = next_n) {
- next_n = agnxtnode(n);
- agdelnode(n);
- }
-
- aginternalmapclose(g);
- agmethod_delete(g, g);
-
- assert(dtsize(g->n_id) == 0);
- agdtclose(g, g->n_id);
- assert(dtsize(g->n_seq) == 0);
- agdtclose(g, g->n_seq);
-
- assert(dtsize(g->e_id) == 0);
- agdtclose(g, g->e_id);
- assert(dtsize(g->e_seq) == 0);
- agdtclose(g, g->e_seq);
-
- assert(dtsize(g->g_dict) == 0);
- agdtclose(g, g->g_dict);
-
- if (g->desc.has_attrs)
- agraphattr_delete(g);
- agrecclose((Agobj_t *) g);
- agfreeid(g, AGRAPH, AGID(g));
-
- if (par) {
- agdelsubg(par, g);
- agfree(par, g);
- } else {
- Agmemdisc_t *memdisc;
- void *memclos, *clos;
- while (g->clos->cb)
- agpopdisc(g, g->clos->cb->f);
- AGDISC(g, id)->close(AGCLOS(g, id));
- agstrclose(g);
- memdisc = AGDISC(g, mem);
- memclos = AGCLOS(g, mem);
- clos = g->clos;
- (memdisc->free) (memclos, g);
- (memdisc->free) (memclos, clos);
- }
- return SUCCESS;
-}
-
-unsigned long agnextseq(Agraph_t * g, int objtype)
-{
- return ++(g->clos->seq[objtype]);
-}
-
-int agnnodes(Agraph_t * g)
-{
- return dtsize(g->n_id);
-}
-
-int agnedges(Agraph_t * g)
-{
- Agnode_t *n;
- int rv = 0;
-
- for (n = agfstnode(g); n; n = agnxtnode(n))
- rv += agdegree(n, FALSE, TRUE); /* must use OUT to get self-arcs */
- return rv;
-}
-
-
-int agisflattened(Agraph_t * g)
-{
- return g->desc.flatlock;
-}
-
-int agisdirected(Agraph_t * g)
-{
- return g->desc.directed;
-}
-
-int agisundirected(Agraph_t * g)
-{
- return NOT(agisdirected(g));
-}
-
-int agisstrict(Agraph_t * g)
-{
- return g->desc.strict;
-}
-
-int agdegree(Agnode_t * n, int want_in, int want_out)
-{
- Agedge_t *e;
- int rv = 0;
-
- if (want_in)
- for (e = agfstin(n); e; e = agnxtin(e))
- rv++;
- if (want_out)
- for (e = agfstout(n); e; e = agnxtout(e))
- rv++;
- return rv;
-}
-
-
-/* directed, strict, flatlock, maingraph */
-Agdesc_t Agdirected = { 1, 0, 0, 1 };
-Agdesc_t Agstrictdirected = { 1, 1, 0, 1 };
-Agdesc_t Agundirected = { 0, 0, 0, 1 };
-Agdesc_t Agstrictundirected = { 0, 1, 0, 1 };
-
-Agdisc_t AgDefaultDisc = { &AgMemDisc, &AgIdDisc, &AgIoDisc };
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include <stdio.h>
-#include "aghdr.h"
-
-/* a default ID allocator that works off the shared string lib */
-
-static void *idopen(Agraph_t * g)
-{
- return g;
-}
-
-static long idmap(void *state, int objtype, char *str, unsigned long *id,
- int createflag)
-{
- char *s;
- static unsigned long ctr = 1;
-
- NOTUSED(objtype);
- if (str) {
- Agraph_t *g;
- g = state;
- if (createflag)
- s = agstrdup(g, str);
- else
- s = agstrbind(g, str);
- *id = (unsigned long) s;
- } else {
- *id = ctr;
- ctr += 2;
- }
- return TRUE;
-}
-
- /* we don't allow users to explicitly set IDs, either */
-static long idalloc(void *state, int objtype, unsigned long request)
-{
- NOTUSED(state);
- NOTUSED(objtype);
- NOTUSED(request);
- return FALSE;
-}
-
-static void idfree(void *state, int objtype, unsigned long id)
-{
- NOTUSED(objtype);
- if (id % 2 == 0)
- agstrfree((Agraph_t *) state, (char *) id);
-}
-
-static char *idprint(void *state, int objtype, unsigned long id)
-{
- NOTUSED(state);
- NOTUSED(objtype);
- if (id % 2 == 0)
- return (char *) id;
- else
- return NILstr;
-}
-
-static void idclose(void *state)
-{
- NOTUSED(state);
-}
-
-Agiddisc_t AgIdDisc = {
- idopen,
- idmap,
- idalloc,
- idfree,
- idprint,
- idclose
-};
-
-/* aux functions incl. support for disciplines with anonymous IDs */
-
-int agmapnametoid(Agraph_t * g, int objtype, char *str,
- unsigned long *result, int createflag)
-{
- int rv;
-
- if (str && (str[0] != LOCALNAMEPREFIX)) {
- rv = AGDISC(g, id)->map(AGCLOS(g, id), objtype, str, result,
- createflag);
- if (rv)
- return rv;
- }
-
- /* either an internal ID, or disc. can't map strings */
- if (str) {
- rv = aginternalmaplookup(g, objtype, str, result);
- if (rv)
- return rv;
- } else
- rv = 0;
-
- if (createflag) {
- /* get a new anonymous ID, and store in the internal map */
- rv = AGDISC(g, id)->map(AGCLOS(g, id), objtype, NILstr, result,
- createflag);
- if (rv && str)
- aginternalmapinsert(g, objtype, str, *result);
- }
- return rv;
-}
-
-int agallocid(Agraph_t * g, int objtype, unsigned long request)
-{
- return AGDISC(g, id)->alloc(AGCLOS(g, id), objtype, request);
-}
-
-void agfreeid(Agraph_t * g, int objtype, unsigned long id)
-{
- (void) aginternalmapdelete(g, objtype, id);
- (AGDISC(g, id)->free) (AGCLOS(g, id), objtype, id);
-}
-
-char *agnameof(void *obj)
-{
- Agraph_t *g;
- char *rv;
- char buf[32];
-
- /* perform internal lookup first */
- g = agraphof(obj);
- if ((rv = aginternalmapprint(g, AGTYPE(obj), AGID(obj))))
- return rv;
-
- if (AGDISC(g, id)->print) {
- if ((rv =
- AGDISC(g, id)->print(AGCLOS(g, id), AGTYPE(obj), AGID(obj))))
- return rv;
- }
- if (AGTYPE(obj) != AGEDGE)
- sprintf(buf, "%c%ld", LOCALNAMEPREFIX, AGID(obj));
- else
- buf[0] = 0;
- return agstrdup(g, buf);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-typedef struct IMapEntry_s {
- Dtlink_t namedict_link;
- Dtlink_t iddict_link;
- unsigned long id;
- char *str;
-} IMapEntry_t;
-
-static int idcmpf(Dict_t * d, void *arg_p0, void *arg_p1, Dtdisc_t * disc)
-{
- IMapEntry_t *p0, *p1;
-
- NOTUSED(d);
- p0 = arg_p0;
- p1 = arg_p1;
- NOTUSED(disc);
- return (p0->id - p1->id);
-}
-
-/* note, OK to compare pointers into shared string pool
- * but can't probe with an arbitrary string pointer
- */
-static int namecmpf(Dict_t * d, void *arg_p0, void *arg_p1,
- Dtdisc_t * disc)
-{
- IMapEntry_t *p0, *p1;
-
- NOTUSED(d);
- p0 = arg_p0;
- p1 = arg_p1;
- NOTUSED(disc);
- return (p0->str - p1->str);
-}
-
-static Dtdisc_t LookupByName = {
- 0, /* object ptr is passed as key */
- 0, /* size (ignored) */
- offsetof(IMapEntry_t, namedict_link),
- NIL(Dtmake_f),
- NIL(Dtfree_f),
- namecmpf,
- NIL(Dthash_f),
- agdictobjmem,
- NIL(Dtevent_f)
-};
-
-static Dtdisc_t LookupById = {
- 0, /* object ptr is passed as key */
- 0, /* size (ignored) */
- offsetof(IMapEntry_t, iddict_link),
- NIL(Dtmake_f),
- NIL(Dtfree_f),
- idcmpf,
- NIL(Dthash_f),
- agdictobjmem,
- NIL(Dtevent_f)
-};
-
-int aginternalmaplookup(Agraph_t * g, int objtype, char *str,
- unsigned long *result)
-{
- Dict_t *d;
- IMapEntry_t *sym, template;
- char *search_str;
-
- if (objtype == AGINEDGE)
- objtype = AGEDGE;
- if ((d = g->clos->lookup_by_name[objtype])) {
- if ((search_str = agstrbind(g, str))) {
- template.str = search_str;
- sym = (IMapEntry_t *) dtsearch(d, &template);
- if (sym) {
- *result = sym->id;
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-/* caller GUARANTEES that this is a new entry */
-void aginternalmapinsert(Agraph_t * g, int objtype, char *str,
- unsigned long id)
-{
- IMapEntry_t *ent;
- Dict_t *d_name_to_id, *d_id_to_name;
-
- ent = AGNEW(g, IMapEntry_t);
- ent->id = id;
- ent->str = agstrdup(g, str);
-
- if (objtype == AGINEDGE)
- objtype = AGEDGE;
- if ((d_name_to_id = g->clos->lookup_by_name[objtype]) == NIL(Dict_t *))
- d_name_to_id = g->clos->lookup_by_name[objtype] =
- agdtopen(g, &LookupByName, Dttree);
- if ((d_id_to_name = g->clos->lookup_by_id[objtype]) == NIL(Dict_t *))
- d_id_to_name = g->clos->lookup_by_id[objtype] =
- agdtopen(g, &LookupById, Dttree);
- dtinsert(d_name_to_id, ent);
- dtinsert(d_id_to_name, ent);
-}
-
-static IMapEntry_t *find_isym(Agraph_t * g, int objtype, unsigned long id)
-{
- Dict_t *d;
- IMapEntry_t *isym, itemplate;
-
- if (objtype == AGINEDGE)
- objtype = AGEDGE;
- if ((d = g->clos->lookup_by_id[objtype])) {
- itemplate.id = id;
- isym = (IMapEntry_t *) dtsearch(d, &itemplate);
- } else
- isym = NIL(IMapEntry_t *);
- return isym;
-}
-
-char *aginternalmapprint(Agraph_t * g, int objtype, unsigned long id)
-{
- IMapEntry_t *isym;
-
- if ((isym = find_isym(g, objtype, id)))
- return isym->str;
- return NILstr;
-}
-
-
-int aginternalmapdelete(Agraph_t * g, int objtype, unsigned long id)
-{
- IMapEntry_t *isym;
-
- if (objtype == AGINEDGE)
- objtype = AGEDGE;
- if ((isym = find_isym(g, objtype, id))) {
- dtdelete(g->clos->lookup_by_name[objtype], isym);
- dtdelete(g->clos->lookup_by_id[objtype], isym);
- agstrfree(g, isym->str);
- agfree(g, isym);
- return TRUE;
- }
- return FALSE;
-}
-
-void aginternalmapclearlocalnames(Agraph_t * g)
-{
- int i;
- IMapEntry_t *sym, *nxt;
- Dict_t **d_name;
- /* Dict_t **d_id; */
-
- Ag_G_global = g;
- d_name = g->clos->lookup_by_name;
- /* d_id = g->clos->lookup_by_id; */
- for (i = 0; i < 3; i++) {
- if (d_name[i]) {
- for (sym = dtfirst(d_name[i]); sym; sym = nxt) {
- nxt = dtnext(d_name[i], sym);
- if (sym->str[0] == LOCALNAMEPREFIX)
- aginternalmapdelete(g, i, sym->id);
- }
- }
- }
-}
-
-static void closeit(Dict_t ** d)
-{
- int i;
-
- for (i = 0; i < 3; i++) {
- if (d[i]) {
- dtclose(d[i]);
- d[i] = NIL(Dict_t *);
- }
- }
-}
-
-void aginternalmapclose(Agraph_t * g)
-{
- Ag_G_global = g;
- closeit(g->clos->lookup_by_name);
- closeit(g->clos->lookup_by_id);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-#ifdef WIN32
-#include <compat.h>
-#include <io.h>
-#endif
-#include <stdio.h>
-#include "aghdr.h"
-
-/* experimental ICONV code - probably should be removed - JCE */
-#undef HAVE_ICONV
-
-#ifdef HAVE_ICONV
-#include <iconv.h>
-#include <langinfo.h>
-#include <errno.h>
-#endif
-
-#ifdef HAVE_ICONV
-static int iofreadiconv(void *chan, char *buf, int bufsize)
-{
-#define CHARBUFSIZE 30
- static char charbuf[CHARBUFSIZE];
- static iconv_t cd = NULL;
- char *inbuf, *outbuf, *readbuf;
- size_t inbytesleft, outbytesleft, readbytesleft, resbytes, result;
- int fd;
-
- if (!cd) {
- cd = iconv_open(nl_langinfo(CODESET), "UTF-8");
- }
- fd = fileno((FILE *) chan);
- readbuf = inbuf = charbuf;
- readbytesleft = CHARBUFSIZE;
- inbytesleft = 0;
- outbuf = buf;
- outbytesleft = bufsize - 1;
- while (1) {
- if ((result = read(fd, readbuf++, 1)) != 1)
- break;
- readbytesleft--;
- inbytesleft++;
- result = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
- if (result != -1) {
- readbuf = inbuf = charbuf;
- readbytesleft = CHARBUFSIZE;
- inbytesleft = 0;
- } else if (errno != EINVAL)
- break;
- }
- *outbuf = '\0';
- resbytes = bufsize - 1 - outbytesleft;
- if (resbytes)
- result = resbytes;
- return result;
-}
-#endif
-
-static int iofread(void *chan, char *buf, int bufsize)
-{
- return read(fileno((FILE *) chan), buf, bufsize);
- /* return fread(buf, 1, bufsize, (FILE*)chan); */
-}
-
-/* default IO methods */
-static int ioputstr(void *chan, char *str)
-{
- return fputs(str, (FILE *) chan);
-}
-
-static int ioflush(void *chan)
-{
- return fflush((FILE *) chan);
-}
-
-/* Agiodisc_t AgIoDisc = { iofreadiconv, ioputstr, ioflush }; */
-Agiodisc_t AgIoDisc = { iofread, ioputstr, ioflush };
+++ /dev/null
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@/@PACKAGE@
-
-Name: libagraph
-Description: Graph library (file i/o, dot language parsing, graph, subgraph, node, edge, attribute, data structure manipulation)
-Version: @VERSION@
-Libs: -L${libdir} -lagraph -lcdt
-Cflags: -I${includedir}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include <stdio.h>
-#include "agraph.h"
-
-static void prstats(Agraph_t * g, int verbose);
-static void do_it(Agraph_t * g, int dostat);
-
-
-static void my_ins(Agobj_t * obj, void *context)
-{
- Agnode_t *n;
-
- if (AGTYPE(obj) == AGNODE) {
- n = (Agnode_t *) obj;
- fprintf(stderr, "%s initialized with label %s\n", agnameof(n),
- agget(n, "label"));
- }
-}
-
-static Agcbdisc_t mydisc = { {0, 0, 0}, {my_ins, 0, 0}, {0, 0, 0} };
-
-main(int argc, char **argv)
-{
- Agraph_t *g, *prev;
- int dostat;
-
- if (argc > 1)
- dostat = atoi(argv[1]);
- else
- dostat = 0;
-
- prev = agopen("some_name", Agdirected, NIL(Agdisc_t *));
- agcallbacks(prev, FALSE);
- agpushdisc(prev, &mydisc, NIL(void *));
- while (g = agconcat(prev, stdin, NIL(Agdisc_t *))) {
- /*do_it(g, dostat); */
- }
- /*agwrite(prev,stdout); */
- fprintf(stderr, "ready to go, computer fans\n");
- agcallbacks(prev, TRUE);
- agclose(prev);
- return 1;
-}
-
-static void prstats(Agraph_t * g, int verbose)
-{
-#ifdef HAVE_VMALLOC
- Vmstat_t ss, *s;
- vmstat(g->cmn->heap, &ss);
- s = &ss;
- if (verbose)
- fprintf(stderr,
- "n_busy %d n_free %d s_busy %d s_free %d m_busy %d m_free %d n_seg %d extent %d\n",
- s->n_busy, s->n_free, s->s_busy, s->s_free, s->m_busy,
- s->m_free, s->n_seg, s->extent);
- else
- fprintf(stderr, "%d (%d,%d)\n", s->extent, s->s_busy, s->s_free);
-#endif
-}
-
-static void do_it(Agraph_t * g, int dostat)
-{
- if (dostat)
- agflatten(g, TRUE);
- agwrite(g, stdout);
- if (dostat)
- prstats(g, dostat > 1);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This defeats the <malloc.h> that yacc generated code includes */
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/* memory management discipline and entry points */
-
-#if (HAVE_AST || HAVE_VMALLOC)
-
- /* vmalloc based allocator */
-static void *memopen(void)
-{
-#if DEBUG || MEMDEBUG
- return vmopen(Vmdcheap, Vmdebug,
- VM_MTDEBUG | VM_DBCHECK | VM_DBABORT | VM_TRACE);
-#else
- return vmopen(Vmdcheap, Vmbest, VM_MTBEST);
-#endif
-}
-
-static void *memalloc(void *heap, size_t request)
-{
- void *rv;
- rv = vmalloc((Vmalloc_t *) heap, request);
- memset(rv, 0, request);
- return rv;
-}
-
-static void *memresize(void *heap, void *ptr, size_t oldsize,
- size_t request)
-{
- void *rv;
-
- rv = vmresize((Vmalloc_t *) heap, ptr, request, VM_RSCOPY | VM_RSZERO);
- return rv;
-}
-
-static void memfree(void *heap, void *ptr)
-{
- vmfree((Vmalloc_t *) heap, ptr);
-}
-
-static void memclose(void *heap)
-{
- vmclose((Vmalloc_t *) heap);
-}
-
-Agmemdisc_t AgMemDisc =
- { memopen, memalloc, memresize, memfree, memclose };
-
-#else
-
- /* malloc based allocator */
-
-static void *memopen(void)
-{
- return NIL(void *);
-}
-
-static void *memalloc(void *heap, size_t request)
-{
- void *rv;
-
- NOTUSED(heap);
- rv = malloc(request);
- memset(rv, 0, request);
- return rv;
-}
-
-static void *memresize(void *heap, void *ptr, size_t oldsize,
- size_t request)
-{
- void *rv;
-
- NOTUSED(heap);
- rv = realloc(ptr, request);
- if (request > oldsize)
- memset((char *) rv + oldsize, 0, request - oldsize);
- return rv;
-}
-
-static void memfree(void *heap, void *ptr)
-{
- NOTUSED(heap);
- free(ptr);
-}
-
-#ifndef WRONG
-#define memclose 0
-#else
-static void memclose(void *heap)
-{
- NOTUSED(heap);
-}
-#endif
-
-Agmemdisc_t AgMemDisc =
- { memopen, memalloc, memresize, memfree, memclose };
-
-#endif
-
-
-void *agalloc(Agraph_t * g, size_t size)
-{
- void *mem;
-
- mem = AGDISC(g, mem)->alloc(AGCLOS(g, mem), size);
- if (mem == NIL(void *))
- agerror(AGERROR_MEMORY, "");
- return mem;
-}
-
-void *agrealloc(Agraph_t * g, void *ptr, size_t oldsize, size_t size)
-{
- void *mem;
-
- if (size > 0) {
- if (ptr == 0)
- mem = agalloc(g, size);
- else
- mem =
- AGDISC(g, mem)->resize(AGCLOS(g, mem), ptr, oldsize, size);
- if (mem == NIL(void *))
- agerror(AGERROR_MEMORY, "");
- } else
- mem = NIL(void *);
- return mem;
-}
-
-void agfree(Agraph_t * g, void *ptr)
-{
- if (ptr)
- (AGDISC(g, mem)->free) (AGCLOS(g, mem), ptr);
-}
-
-#ifndef _VMALLOC_H
-struct _vmalloc_s {
- char unused;
-};
-#endif
-struct _vmalloc_s *agheap(Agraph_t * g)
-{
- return AGCLOS(g, mem);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-Agnode_t *agfindnode_by_id(Agraph_t * g, unsigned long id)
-{
- Agnode_t *n;
- static Agnode_t template;
-
- template.base.tag.id = id;
- n = (Agnode_t *) dtsearch(g->n_id, &template);
- return n;
-}
-
-static Agnode_t *agfindnode_by_name(Agraph_t * g, char *name)
-{
- unsigned long id;
-
- if (agmapnametoid(g, AGNODE, name, &id, FALSE))
- return agfindnode_by_id(g, id);
- else
- return NILnode;
-}
-
-Agnode_t *agfstnode(Agraph_t * g)
-{
- return (Agnode_t *) dtfirst(g->n_seq);
-}
-
-Agnode_t *agnxtnode(Agnode_t * n)
-{
- Agraph_t *g;
- g = agraphof(n);
- if (agisflattened(g))
- return AGNEXTNODE(n);
- else {
- return (Agnode_t *) dtnext(g->n_seq, n);
- }
-}
-
-static Agnode_t *newnode(Agraph_t * g, unsigned long id, unsigned long seq)
-{
- Agnode_t *n;
-
- n = agalloc(g, sizeof(Agnode_t));
- AGTYPE(n) = AGNODE;
- AGID(n) = id;
- AGSEQ(n) = seq;
- n->g = g;
- dtinsert(g->n_seq, n);
- dtinsert(g->n_id, n);
- return n;
-}
-
-/* create or bind the given node. it may already exist in the parent. */
-static Agnode_t *mklocalnode(Agraph_t * g, unsigned long id,
- Agnode_t * rootnode, int *isnew)
-{
- Agnode_t *n, *npar;
- Agraph_t *par;
-
- agnotflat(g);
- if (rootnode) {
- if (g->desc.maingraph)
- return rootnode;
- if ((n = agfindnode_by_id(g, id)))
- return n;
- }
- if ((par = agparent(g)))
- npar = mklocalnode(par, id, rootnode, isnew);
- else {
- npar = NILnode;
- *isnew = TRUE;
- }
- n = newnode(g, id, npar ? AGSEQ(npar) : agnextseq(g, AGNODE));
- if (npar)
- AGDATA(n) = AGDATA(npar);
- else {
- if (g->desc.has_attrs)
- (void) agrealbindrec(n, AgDataRecName, sizeof(Agattr_t), FALSE,
- TRUE);
- /* nodeattr_init and method_init will be called later */
- }
- return n;
-}
-
-static Agnode_t *localnode(Agraph_t * g, unsigned long id,
- Agnode_t * rootnode)
-{
- int isnew = FALSE;
- Agnode_t *n;
- n = mklocalnode(g, id, rootnode, &isnew);
- if (isnew) {
- if (g->desc.has_attrs)
- agnodeattr_init(n, TRUE);
- agmethod_init(g, n);
- }
- return n;
-}
-
-Agnode_t *agidnode(Agraph_t * g, unsigned long id, int cflag)
-{
- Agraph_t *root;
- Agnode_t *n, *rootnode;
-
- rootnode = NILnode;
- n = agfindnode_by_id(g, id);
- if ((n == NILnode) && cflag) {
- root = agroot(g);
- if (((g != root) && ((rootnode = agfindnode_by_id(agroot(g), id)))) /*old */
- ||agallocid(g, AGNODE, id)) /* new */
- n = localnode(g, id, rootnode);
- }
- return n;
-}
-
-Agnode_t *agnode(Agraph_t * g, char *name, int cflag)
-{
- Agraph_t *root;
- Agnode_t *n, *rootnode;
- unsigned long id;
-
- if (agmapnametoid(g, AGNODE, name, &id, FALSE)) {
- /* might already exist locally */
- if ((n = agfindnode_by_id(g, id)))
- return n;
-
- /* might already exist globally */
- root = agroot(g);
- if (cflag && (g != root)
- && ((rootnode = agfindnode_by_id(root, id))))
- if ((n = localnode(g, id, rootnode)))
- return n;
- }
-
- if (cflag && agmapnametoid(g, AGNODE, name, &id, TRUE)) /* reserve id */
- return localnode(g, id, NILnode);
-
- return NILnode;
-}
-
-/* removes image of node and its edges from graph.
- caller must ensure arg_n belongs to g. */
-void agdelnodeimage(Agnode_t * n, void *ignored)
-{
- Agraph_t *g;
- Agedge_t *e, *f;
-
- NOTUSED(ignored);
- g = agraphof(n);
- agnotflat(g);
- agflatten_edges(g, n);
-#ifndef NOFLATOPT
- if (n->out)
- assert(AGPREV(n->out) == NILedge);
- for (e = AGFSTOUT(n); e; e = f) {
- f = AGNXTE(e);
- if (f)
- assert(AGPREV(f) == e);
- if (e->node != n)
- agedgesetop(g, AGOPP(e), FALSE);
- agfree(g, e); /* Note, assumes edgepair layout in edge.c */
- }
- if (n->in)
- assert(AGPREV(n->in) == NILedge);
- for (e = AGFSTIN(n); e; e = f) {
- f = AGNXTE(e);
- if (f)
- assert(AGPREV(f) == e);
- if (e->node != n)
- agedgesetop(g, AGOPP(e), FALSE);
- agfree(g, AGIN2OUT(e));
- }
-#else
- for (e = agfstedge(n); e; e = f) {
- f = agnxtedge(e, n);
- agdeledgepair(e);
- }
-#endif
- dtdelete(g->n_seq, n);
- dtdelete(g->n_id, n);
- agfree(g, n);
-}
-
-int agdelnode(Agnode_t * n)
-{
- Agraph_t *g;
- Agedge_t *e, *f;
-
- g = agraphof(n);
- if ((Agnode_t *) dtsearch(g->n_id, n) == NILnode)
- return FAILURE; /* bad arg */
- if (agisarootobj(n)) {
- for (e = agfstedge(n); e; e = f) {
- f = agnxtedge(e, n);
- agdeledge(e);
- }
- if (g->desc.has_attrs)
- agnodeattr_delete(n);
- agmethod_delete(g, n);
- agrecclose((Agobj_t *) n);
- agfreeid(g, AGNODE, AGID(n));
- }
- return agapply(g, (Agobj_t *) n, (agobjfn_t) agdelnodeimage, NILnode,
- FALSE);
-}
-
-static void dict_relabel(Agnode_t * n, void *arg)
-{
- Agraph_t *g;
- unsigned long new_id;
-
- g = agraphof(n);
- new_id = *(unsigned long *) arg;
- agnotflat(g);
- dtdelete(g->n_id, n);
- AGID(n) = new_id;
- dtinsert(g->n_id, n);
-}
-
-int agrelabel_node(Agnode_t * n, char *newname)
-{
- Agraph_t *g;
- unsigned long new_id;
-
- g = agroot(agraphof(n));
- if (agfindnode_by_name(g, newname))
- return FAILURE;
- if (agmapnametoid(g, AGNODE, newname, &new_id, TRUE)) {
- if (agfindnode_by_id(agroot(g), new_id) == NILnode) {
- agfreeid(g, AGNODE, AGID(n));
- agapply(g, (Agobj_t *) n, (agobjfn_t) dict_relabel,
- (void *) &new_id, FALSE);
- return SUCCESS;
- } else {
- agfreeid(g, AGNODE, new_id); /* couldn't use it after all */
- }
- }
- return FAILURE;
-}
-
-/* return a node in <g> that is the image of <arg_n>. */
-Agnode_t *agsubnode(Agraph_t * g, Agnode_t * arg_n, int cflag)
-{
- Agnode_t *n, *npar;
- Agraph_t *par;
-
- n = agfindnode_by_id(g, AGID(arg_n));
-
- if ((n == NILnode) && cflag) {
- if ((par = agparent(g))) {
- if ((npar = agsubnode(par, arg_n, cflag))) {
- n = newnode(g, AGID(npar), AGSEQ(npar));
- AGDATA(n) = AGDATA(npar);
-/* #ifdef MTFHACK */
- n->base.tag.mtflock = npar->base.tag.mtflock;
-/* #endif */
- } /* else someone handed us a flaky ptr in <n> */
- }
- }
- /* else probe failed */
- return n;
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-int agobjidcmpf(Dict_t * dict, void *arg0, void *arg1, Dtdisc_t * disc)
-{
- Agobj_t *obj0, *obj1;
-
- NOTUSED(dict);
- obj0 = arg0;
- obj1 = arg1;
- NOTUSED(disc);
- return AGID(obj0) - AGID(obj1);
-}
-
-int agobjseqcmpf(Dict_t * dict, void *arg0, void *arg1, Dtdisc_t * disc)
-{
- Agobj_t *obj0, *obj1;
-
- NOTUSED(dict);
- obj0 = arg0;
- obj1 = arg1;
- NOTUSED(disc);
- return AGSEQ(obj0) - AGSEQ(obj1);
-}
-
-Agobj_t *agrebind(Agraph_t * g, Agobj_t * obj)
-{
- Agraph_t *h;
- Agobj_t *nobj;
-
- h = agraphof(obj);
- if (h == g)
- return obj;
-
- switch (AGTYPE(obj)) {
- case AGNODE:
- nobj = (Agobj_t *) agsubnode(g, (Agnode_t *) obj, FALSE);
- break;
- case AGINEDGE:
- case AGOUTEDGE:
- nobj = (Agobj_t *) agsubedge(g, (Agedge_t *) obj, FALSE);
- break;
- case AGRAPH:
- nobj = (Agobj_t *) g;
- break;
- default:
- nobj = 0;
- agerror(AGERROR_BADOBJ, "agrebind");
- }
- return nobj;
-}
-
-int agdelete(Agraph_t * g, void *obj)
-{
- Agraph_t *h;
-
- h = agraphof(obj);
- if ((g != h)
- && ((AGTYPE((Agobj_t *) obj) != AGRAPH) || (g != agparent(h))))
- agerror(AGERROR_WRONGGRAPH, "agdelete");
-
- switch (AGTYPE((Agobj_t *) obj)) {
- case AGNODE:
- return agdelnode(obj);
- case AGINEDGE:
- case AGOUTEDGE:
- return agdeledge(obj);
- case AGRAPH:
- return agclose(obj);
- default:
- agerror(AGERROR_BADOBJ, "agdelete");
- }
- return SUCCESS; /* not reached */
-}
-
-int agrename(Agobj_t * obj, char *newname)
-{
- Agraph_t *g;
- unsigned long old_id, new_id;
-
- switch (AGTYPE(obj)) {
- case AGRAPH:
- old_id = AGID(obj);
- g = agraphof(obj);
- /* can we reserve the id corresponding to newname? */
- if (agmapnametoid(agroot(g), AGTYPE(obj), newname,
- &new_id, FALSE) == 0)
- return FAILURE;
- if (new_id == old_id)
- return SUCCESS;
- if (agmapnametoid(agroot(g), AGTYPE(obj), newname,
- &new_id, TRUE) == 0)
- return FAILURE;
- if (agparent(g) && agidsubg(agparent(g), new_id, 0))
- return FAILURE;
- agfreeid(g, AGRAPH, old_id);
- AGID(g) = new_id;
- break;
- case AGNODE:
- return agrelabel_node((Agnode_t *) obj, newname);
- case AGINEDGE:
- case AGOUTEDGE:
- return FAILURE;
- }
- return SUCCESS;
-}
-
-/* perform initialization/update/finalization method invocation.
- * skip over nil pointers to next method below.
- */
-
-void agmethod_init(Agraph_t * g, void *obj)
-{
- if (g->clos->callbacks_enabled)
- aginitcb(obj, g->clos->cb);
- else
- agrecord_callback(obj, CB_INITIALIZE, NILsym);
-}
-
-void aginitcb(void *obj, Agcbstack_t * cbstack)
-{
- agobjfn_t fn;
-
- if (cbstack == NIL(Agcbstack_t *))
- return;
- aginitcb(obj, cbstack->prev);
- fn = NIL(agobjfn_t);
- switch (AGTYPE(obj)) {
- case AGRAPH:
- fn = cbstack->f->graph.ins;
- break;
- case AGNODE:
- fn = cbstack->f->node.ins;
- break;
- case AGEDGE:
- fn = cbstack->f->edge.ins;
- break;
- }
- if (fn)
- fn(obj, cbstack->state);
-}
-
-void agmethod_upd(Agraph_t * g, void *obj, Agsym_t * sym)
-{
- if (g->clos->callbacks_enabled)
- agupdcb(obj, sym, g->clos->cb);
- else
- agrecord_callback(obj, CB_UPDATE, sym);
-}
-
-void agupdcb(void *obj, Agsym_t * sym, Agcbstack_t * cbstack)
-{
- agobjupdfn_t fn;
-
- if (cbstack == NIL(Agcbstack_t *))
- return;
- agupdcb(obj, sym, cbstack->prev);
- fn = NIL(agobjupdfn_t);
- switch (AGTYPE(obj)) {
- case AGRAPH:
- fn = cbstack->f->graph.mod;
- break;
- case AGNODE:
- fn = cbstack->f->node.mod;
- break;
- case AGEDGE:
- fn = cbstack->f->edge.mod;
- break;
- }
- if (fn)
- fn(obj, cbstack->state, sym);
-}
-
-void agmethod_delete(Agraph_t * g, void *obj)
-{
- if (g->clos->callbacks_enabled)
- agdelcb(obj, g->clos->cb);
- else
- agrecord_callback(obj, CB_DELETION, NILsym);
-}
-
-void agdelcb(void *obj, Agcbstack_t * cbstack)
-{
- agobjfn_t fn;
-
- if (cbstack == NIL(Agcbstack_t *))
- return;
- agdelcb(obj, cbstack->prev);
- fn = NIL(agobjfn_t);
- switch (AGTYPE(obj)) {
- case AGRAPH:
- fn = cbstack->f->graph.del;
- break;
- case AGNODE:
- fn = cbstack->f->node.del;
- break;
- case AGEDGE:
- fn = cbstack->f->edge.del;
- break;
- }
- if (fn)
- fn(obj, cbstack->state);
-}
-
-Agraph_t *agraphof(void *obj)
-{
- switch (AGTYPE(obj)) {
- case AGINEDGE:
- case AGOUTEDGE:
- return ((Agedge_t *) obj)->node->g;
- case AGNODE:
- return ((Agnode_t *) obj)->g;
- case AGRAPH:
- return (Agraph_t *) obj;
- default: /* actually can't occur if only 2 bit tags */
- agerror(AGERROR_BADOBJ, "agraphof");
- return NILgraph;
- }
-}
-
-int agisarootobj(void *obj)
-{
- return (agraphof(obj)->desc.maingraph);
-}
-
-/* to manage disciplines */
-
-void agpushdisc(Agraph_t * g, Agcbdisc_t * cbd, void *state)
-{
- Agcbstack_t *stack_ent;
-
- stack_ent = AGNEW(g, Agcbstack_t);
- stack_ent->f = cbd;
- stack_ent->state = state;
- stack_ent->prev = g->clos->cb;
- g->clos->cb = stack_ent;
-}
-
-int agpopdisc(Agraph_t * g, Agcbdisc_t * cbd)
-{
- Agcbstack_t *stack_ent;
-
- stack_ent = g->clos->cb;
- if (stack_ent) {
- if (stack_ent->f == cbd)
- g->clos->cb = stack_ent->prev;
- else {
- while (stack_ent && (stack_ent->prev->f != cbd))
- stack_ent = stack_ent->prev;
- if (stack_ent && stack_ent->prev)
- stack_ent->prev = stack_ent->prev->prev;
- }
- if (stack_ent) {
- agfree(g, stack_ent);
- return SUCCESS;
- }
- }
- return FAILURE;
-}
-
-void *aggetuserptr(Agraph_t * g, Agcbdisc_t * cbd)
-{
- Agcbstack_t *stack_ent;
-
- for (stack_ent = g->clos->cb; stack_ent; stack_ent = stack_ent->prev)
- if (stack_ent->f == cbd)
- return stack_ent->state;
- return NIL(void *);
-}
-
-Dtdisc_t Ag_obj_id_disc = {
- 0, /* pass object ptr */
- 0, /* size (ignored) */
- offsetof(Agobj_t, id_link), /* link offset */
- NIL(Dtmake_f),
- NIL(Dtfree_f),
- agobjidcmpf,
- NIL(Dthash_f),
- agdictobjmem,
- NIL(Dtevent_f)
-};
-
-Dtdisc_t Ag_obj_seq_disc = {
- 0, /* pass object ptr */
- 0, /* size (ignored) */
- offsetof(Agobj_t, seq_link), /* link offset */
- NIL(Dtmake_f),
- NIL(Dtfree_f),
- agobjseqcmpf,
- NIL(Dthash_f),
- agdictobjmem,
- NIL(Dtevent_f)
-};
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-static char DRName[] = "_AG_pending";
-
-typedef struct symlist_s {
- Agsym_t *sym;
- struct symlist_s *link;
-} symlist_t;
-
-/* this record describes one pending callback on one object */
-typedef struct {
- Dtlink_t link;
- unsigned long key; /* universal key for main or sub-object */
- Agobj_t *obj; /* may be a subgraph obj */
- /* i'm sure there are more elegant approaches,but */
- Agraph_t *g_alloc; /* save this, because object may become dead */
- symlist_t *symlist; /* attributes involved */
-} pending_cb_t;
-
-typedef struct {
- Agrec_t h;
- struct {
- Dict_t *g, *n, *e;
- } ins, mod, del;
-} pendingset_t;
-
-static void free_symlist(pending_cb_t * pcb)
-{
- symlist_t *s, *t;
-
- for (s = pcb->symlist; s; s = t) {
- t = s->link;
- agfree(pcb->g_alloc, s);
- }
-}
-
-static void freef(Dict_t * dict, void *ptr, Dtdisc_t * disc)
-{
- pending_cb_t *pcb;
-
- NOTUSED(dict);
- NOTUSED(disc);
- pcb = ptr;
- free_symlist(pcb);
- agfree(pcb->g_alloc, pcb);
-}
-
-static Dtdisc_t Disc = {
- offsetof(pending_cb_t, key), /* sort by 'key' */
- sizeof(unsigned long),
- 0, /* link offset */
- NIL(Dtmake_f),
- freef,
- NIL(Dtcompar_f),
- NIL(Dthash_f)
-};
-
-static Dict_t *dictof(pendingset_t * ds, Agobj_t * obj, int kind)
-{
- Dict_t **dict_ref = NIL(Dict_t **);
-
- dict_ref = 0;
- switch (AGTYPE(obj)) {
- case AGRAPH:
- switch (kind) {
- case CB_INITIALIZE:
- dict_ref = &(ds->ins.g);
- break;
- case CB_UPDATE:
- dict_ref = &(ds->mod.g);
- break;
- case CB_DELETION:
- dict_ref = &(ds->del.g);
- break;
- default:
- break;
- }
- break;
- case AGNODE:
- switch (kind) {
- case CB_INITIALIZE:
- dict_ref = &(ds->ins.n);
- break;
- case CB_UPDATE:
- dict_ref = &(ds->mod.n);
- break;
- case CB_DELETION:
- dict_ref = &(ds->del.n);
- break;
- default:
- break;
- }
- break;
- case AGEDGE:
- switch (kind) {
- case CB_INITIALIZE:
- dict_ref = &(ds->ins.e);
- break;
- case CB_UPDATE:
- dict_ref = &(ds->mod.e);
- break;
- case CB_DELETION:
- dict_ref = &(ds->del.e);
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- if (dict_ref == 0)
- agerror(AGERROR_BADOBJ, "pend dictof");
- if (*dict_ref == NIL(Dict_t *))
- *dict_ref = agdtopen(agraphof(obj), &Disc, Dttree);
- return *dict_ref;
-}
-
-static unsigned long genkey(Agobj_t * obj)
-{
- return obj->tag.id;
-}
-
-static pending_cb_t *lookup(Dict_t * dict, Agobj_t * obj)
-{
- pending_cb_t key, *rv;
-
- key.key = genkey(obj);
- rv = (pending_cb_t *) dtsearch(dict, &key);
- return rv;
-}
-
-static void record_sym(Agobj_t * obj, pending_cb_t * handle,
- Agsym_t * optsym)
-{
- symlist_t *sym, *nsym, *psym;
-
- psym = NIL(symlist_t *);
- for (sym = handle->symlist; sym; psym = sym, sym = sym->link) {
- if (sym->sym == optsym)
- break;
- if (sym == NIL(symlist_t *)) {
- nsym = agalloc(agraphof(obj), sizeof(symlist_t));
- nsym->sym = optsym;
- if (psym)
- psym->link = nsym;
- else
- handle->symlist = nsym;
- }
- /* else we already have a callback registered */
- }
-}
-
-static pending_cb_t *insert(Dict_t * dict, Agobj_t * obj, Agsym_t * optsym)
-{
- pending_cb_t *handle;
- handle = agalloc(agraphof(obj), sizeof(pending_cb_t));
- handle->obj = obj;
- handle->key = genkey(obj);
- handle->g_alloc = agraphof(obj);
- if (optsym) {
- handle->symlist =
- (symlist_t *) agalloc(handle->g_alloc, sizeof(symlist_t));
- handle->symlist->sym = optsym;
- }
- dtinsert(dict, handle);
- return handle;
-}
-
-static void purge(Dict_t * dict, Agobj_t * obj)
-{
- pending_cb_t *handle;
-
- if ((handle = lookup(dict, obj))) {
- dtdelete(dict, handle);
- }
-}
-
-void agrecord_callback(Agobj_t * obj, int kind, Agsym_t * optsym)
-{
- pendingset_t *pending;
- Dict_t *dict;
- pending_cb_t *handle;
- Agraph_t *g;
-
- g = agraphof(obj);
- pending =
- (pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t), FALSE);
-
- switch (kind) {
- case CB_INITIALIZE:
- assert(lookup(dictof(pending, obj, CB_UPDATE), obj) == 0);
- assert(lookup(dictof(pending, obj, CB_DELETION), obj) == 0);
- dict = dictof(pending, obj, CB_INITIALIZE);
- handle = lookup(dict, obj);
- if (handle == 0)
- handle = insert(dict, obj, optsym);
- break;
- case CB_UPDATE:
- if (lookup(dictof(pending, obj, CB_INITIALIZE), obj))
- break;
- if (lookup(dictof(pending, obj, CB_DELETION), obj))
- break;
- dict = dictof(pending, obj, CB_UPDATE);
- handle = lookup(dict, obj);
- if (handle == 0)
- handle = insert(dict, obj, optsym);
- record_sym(obj, handle, optsym);
- break;
- case CB_DELETION:
- purge(dictof(pending, obj, CB_INITIALIZE), obj);
- purge(dictof(pending, obj, CB_UPDATE), obj);
- dict = dictof(pending, obj, CB_DELETION);
- handle = lookup(dict, obj);
- if (handle == 0)
- handle = insert(dict, obj, optsym);
- break;
- default:
- agerror(AGERROR_BADOBJ, "agrecord_callback");
- }
-}
-
-static void cb(Dict_t * dict, int callback_kind)
-{
- pending_cb_t *pcb;
- Agraph_t *g;
- symlist_t *psym;
- Agcbstack_t *stack;
-
- if (dict)
- while ((pcb = (pending_cb_t *) dtfirst(dict))) {
- g = pcb->g_alloc;
- stack = g->clos->cb;
- switch (callback_kind) {
- case CB_INITIALIZE:
- aginitcb(pcb->obj, stack);
- break;
- case CB_UPDATE:
- for (psym = pcb->symlist; psym; psym = psym->link)
- agupdcb(pcb->obj, psym->sym, stack);
- break;
- case CB_DELETION:
- agdelcb(pcb->obj, stack);
- break;
- }
- dtdelete(dict, pcb);
- }
-}
-
-static void agrelease_callbacks(Agraph_t * g)
-{
- pendingset_t *pending;
- if (NOT(g->clos->callbacks_enabled)) {
- g->clos->callbacks_enabled = TRUE;
- pending =
- (pendingset_t *) agbindrec(g, DRName, sizeof(pendingset_t),
- FALSE);
- /* this destroys objects in the opposite of their order of creation */
- cb(pending->ins.g, CB_INITIALIZE);
- cb(pending->ins.n, CB_INITIALIZE);
- cb(pending->ins.e, CB_INITIALIZE);
-
- cb(pending->mod.g, CB_UPDATE);
- cb(pending->mod.n, CB_UPDATE);
- cb(pending->mod.e, CB_UPDATE);
-
- cb(pending->del.e, CB_DELETION);
- cb(pending->del.n, CB_DELETION);
- cb(pending->del.g, CB_DELETION);
- }
-}
-
-int agcallbacks(Agraph_t * g, int flag)
-{
- if (flag && NOT(g->clos->callbacks_enabled))
- agrelease_callbacks(g);
- if (g->clos->callbacks_enabled) {
- g->clos->callbacks_enabled = flag;
- return TRUE;
- }
- g->clos->callbacks_enabled = flag;
- return FALSE;
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/*
- * run time records
- */
-
-static void set_data(Agobj_t * obj, Agrec_t * data, int mtflock)
-{
- Agedge_t *e;
-
- obj->data = data;
- obj->tag.mtflock = mtflock;
- if ((AGTYPE(obj) == AGINEDGE) || (AGTYPE(obj) == AGOUTEDGE)) {
- e = agopp((Agedge_t *) obj);
- AGDATA(e) = data;
- e->base.tag.mtflock = mtflock;
- }
-}
-
-/* find record in circular list and do optional move-to-front */
-Agrec_t *aggetrec(void *obj, char *name, int mtf)
-{
- Agobj_t *hdr;
- Agrec_t *d, *first;
-
- hdr = (Agobj_t *) obj;
- first = d = hdr->data;
- while (d) {
- if ((d->name == name) || streq(name, d->name))
- break;
- d = d->next;
- if (d == first) {
- d = NIL(Agrec_t *);
- break;
- }
- }
- if (d) {
- if (hdr->tag.mtflock) {
- if (mtf && (hdr->data != d))
- agerror(AGERROR_MTFLOCK, "");
- } else {
- if ((d != first) || (mtf != hdr->tag.mtflock))
- set_data(hdr, d, mtf); /* Always optimize */
- }
- }
- return d;
-}
-
-/* insert the record in data list of this object (only) */
-static void objputrec(Agobj_t * obj, void *arg)
-{
- Agrec_t *firstrec, *newrec;
-
- newrec = arg;
- firstrec = obj->data;
- if (firstrec == NIL(Agrec_t *))
- newrec->next = newrec; /* 0 elts */
- else {
- if (firstrec->next == firstrec) {
- firstrec->next = newrec; /* 1 elt */
- newrec->next = firstrec;
- } else {
- newrec->next = firstrec->next;
- firstrec->next = newrec;
- }
- }
- if (NOT(obj->tag.mtflock))
- set_data(obj, newrec, FALSE);
-}
-
-/* attach a new record of the given size to the object.
- * for the first record, this may involve visiting all reps in the graph.
- */
-void *agrealbindrec(void *arg_obj, char *recname, unsigned int recsize,
- int mtf, int norecur)
-{
- Agraph_t *g;
- Agobj_t *obj;
- Agrec_t *rec;
-
- obj = (Agobj_t *) arg_obj;
- g = agraphof(obj);
- rec = aggetrec(obj, recname, FALSE);
- if ((rec == NIL(Agrec_t *)) && (recsize > 0)) {
- rec = (Agrec_t *) agalloc(g, (int) recsize);
- rec->name = agstrdup(g, recname);
- switch (obj->tag.objtype) {
- case AGRAPH:
- objputrec(obj, rec);
- break;
- case AGNODE:
- if (norecur || obj->data)
- objputrec(obj, rec);
- else
- agapply(agroot(g), obj, objputrec, rec, TRUE);
- break;
- case AGINEDGE:
- case AGOUTEDGE:
- if (norecur || obj->data)
- objputrec(obj, rec);
- else
- agapply(agroot(g), obj, objputrec, rec, TRUE);
- break;
- }
- }
- if (mtf)
- aggetrec(arg_obj, recname, TRUE);
- return (void *) rec;
-}
-
-void *agbindrec(void *arg_obj, char *recname, unsigned int recsize,
- int mtf)
-{
- return agrealbindrec(arg_obj, recname, recsize, mtf, FALSE);
-}
-
-/* if obj points to rec, move its data pointer. break any mtf lock(?) */
-static void objdelrec(Agobj_t * obj, void *arg_rec)
-{
- Agrec_t *rec = (Agrec_t *) arg_rec, *newrec;
- if (obj->data == rec) {
- if (rec->next == rec)
- newrec = NIL(Agrec_t *);
- else
- newrec = rec->next;
- set_data(obj, newrec, FALSE);
- }
-}
-
-/* delete a record from a circular data list */
-static void listdelrec(Agobj_t * obj, Agrec_t * rec)
-{
- Agrec_t *prev;
-
- prev = obj->data;
- while (prev->next != rec) {
- prev = prev->next;
- assert(prev != obj->data);
- }
- /* following is a harmless no-op if the list is trivial */
- prev->next = rec->next;
-}
-
-int agdelrec(void *arg_obj, char *name)
-{
- Agobj_t *obj;
- Agrec_t *rec;
- Agraph_t *g;
-
- obj = (Agobj_t *) arg_obj;
- g = agraphof(obj);
- rec = aggetrec(obj, name, FALSE);
- if (rec) {
- listdelrec(obj, rec); /* zap it from the circular list */
- switch (obj->tag.objtype) { /* refresh any stale pointers */
- case AGRAPH:
- objdelrec(obj, rec);
- break;
- case AGNODE:
- case AGINEDGE:
- case AGOUTEDGE:
- agapply(agroot(g), obj, objdelrec, rec, FALSE);
- break;
- }
- agstrfree(g, rec->name);
- agfree(g, rec);
- return SUCCESS;
- } else
- return FAILURE;
-}
-
-static void simple_delrec(Agobj_t * obj, void *rec_name)
-{
- agdelrec(obj, rec_name);
-}
-
-#ifdef OLD
-void agclean(Agraph_t * g, char *graphdata, char *nodedata, char *edgedata)
-{
- Agnode_t *n;
- Agedge_t *e;
-
- if (nodedata || edgedata) {
- for (n = agfstnode(g); n; n = agnxtnode(n)) {
- if (edgedata)
- for (e = agfstout(n); e; e = agnxtout(e)) {
- agdelrec(e, edgedata);
- }
- if (nodedata)
- agdelrec(n, nodedata);
- }
- }
- agdelrec(g, graphdata);
-}
-#endif
-
-void aginit(Agraph_t * g, int kind, char *rec_name, int rec_size, int mtf)
-{
- Agnode_t *n;
- Agedge_t *e;
-
- switch (kind) {
- case AGRAPH:
- agbindrec(g, rec_name, rec_size, mtf);
- break;
- case AGNODE:
- case AGOUTEDGE:
- case AGINEDGE:
- for (n = agfstnode(g); n; n = agnxtnode(n))
- if (kind == AGNODE)
- agbindrec(n, rec_name, rec_size, mtf);
- else {
- for (e = agfstout(n); e; e = agnxtout(e))
- agbindrec(e, rec_name, rec_size, mtf);
- }
- break;
- default:
- break;
- }
-}
-
-void agclean(Agraph_t * g, int kind, char *rec_name)
-{
- Agnode_t *n;
- Agedge_t *e;
-
- switch (kind) {
- case AGRAPH:
- agapply(g, (Agobj_t *) g, simple_delrec, rec_name, TRUE);
- break;
- case AGNODE:
- case AGOUTEDGE:
- case AGINEDGE:
- for (n = agfstnode(g); n; n = agnxtnode(n))
- if (kind == AGNODE)
- agdelrec(n, rec_name);
- else {
- for (e = agfstout(n); e; e = agnxtout(e))
- agdelrec(e, rec_name);
- }
- break;
- default:
- break;
- }
-}
-
-void agrecclose(Agobj_t * obj)
-{
- Agraph_t *g;
- Agrec_t *rec, *nrec;
-
- g = agraphof(obj);
- if ((rec = obj->data)) {
- do {
- nrec = rec->next;
- agstrfree(g, rec->name);
- agfree(g, rec);
- rec = nrec;
- } while (rec != obj->data);
- }
- obj->data = NIL(Agrec_t *);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-/*
- * reference counted strings.
- */
-
-static unsigned long HTML_BIT; /* msbit of unsigned long */
-static unsigned long CNT_BITS; /* complement of HTML_BIT */
-
-typedef struct refstr_t {
- Dtlink_t link;
- unsigned long refcnt;
- char *s;
- char store[1]; /* this is actually a dynamic array */
-} refstr_t;
-
-static Dtdisc_t Refstrdisc = {
- offsetof(refstr_t, s), /* key */
- -1, /* size */
- 0, /* link offset */
- NIL(Dtmake_f),
- agdictobjfree,
- NIL(Dtcompar_f),
- NIL(Dthash_f),
- agdictobjmem,
- NIL(Dtevent_f)
-};
-
-static Dict_t *Refdict_default;
-
-/* refdict:
- * Return the string dictionary associated with g.
- * If necessary, create it.
- * As a side-effect, set html masks. This assumes 8-bit bytes.
- */
-static Dict_t *refdict(Agraph_t * g)
-{
- Dict_t **dictref;
-
- if (g)
- dictref = &(g->clos->strdict);
- else
- dictref = &Refdict_default;
- if (*dictref == NIL(Dict_t *)) {
- *dictref = agdtopen(g, &Refstrdisc, Dttree);
- HTML_BIT = ((unsigned int) 1) << (sizeof(unsigned int) * 8 - 1);
- CNT_BITS = ~HTML_BIT;
- }
- return *dictref;
-}
-
-void agstrclose(Agraph_t * g)
-{
- agdtclose(g, refdict(g));
-}
-
-static refstr_t *refsymbind(Dict_t * strdict, char *s)
-{
- refstr_t key, *r;
- key.s = s;
- r = (refstr_t *) dtsearch(strdict, &key);
- return r;
-}
-
-static char *refstrbind(Dict_t * strdict, char *s)
-{
- refstr_t *r;
- r = refsymbind(strdict, s);
- if (r)
- return r->s;
- else
- return NIL(char *);
-}
-
-char *agstrbind(Agraph_t * g, char *s)
-{
- return refstrbind(refdict(g), s);
-}
-
-char *agstrdup(Agraph_t * g, char *s)
-{
- refstr_t *r;
- Dict_t *strdict;
- size_t sz;
-
- if (s == NIL(char *))
- return NIL(char *);
- strdict = refdict(g);
- r = refsymbind(strdict, s);
- if (r)
- r->refcnt++;
- else {
- sz = sizeof(refstr_t) + strlen(s);
- if (g)
- r = (refstr_t *) agalloc(g, sz);
- else {
- r = (refstr_t *) malloc(sz);
- if (!r)
- exit(1);
- }
- r->refcnt = 1;
- strcpy(r->store, s);
- r->s = r->store;
- dtinsert(strdict, r);
- }
- return r->s;
-}
-
-char *agstrdup_html(Agraph_t * g, char *s)
-{
- refstr_t *r;
- Dict_t *strdict;
- size_t sz;
-
- if (s == NIL(char *))
- return NIL(char *);
- strdict = refdict(g);
- r = refsymbind(strdict, s);
- if (r)
- r->refcnt++;
- else {
- sz = sizeof(refstr_t) + strlen(s);
- if (g)
- r = (refstr_t *) agalloc(g, sz);
- else {
- r = (refstr_t *) malloc(sz);
- if (!r)
- exit(1);
- }
- r->refcnt = 1 | HTML_BIT;
- strcpy(r->store, s);
- r->s = r->store;
- dtinsert(strdict, r);
- }
- return r->s;
-}
-
-int agstrfree(Agraph_t * g, char *s)
-{
- refstr_t *r;
- Dict_t *strdict;
-
- if (s == NIL(char *))
- return FAILURE;
-
- strdict = refdict(g);
- r = refsymbind(strdict, s);
- if (r && (r->s == s)) {
- r->refcnt--;
- if ((r->refcnt && CNT_BITS) == 0) {
- agdtdelete(g, strdict, r);
- /*
- if (g) agfree(g,r);
- else free(r);
- */
- }
- }
- if (r == NIL(refstr_t *))
- return FAILURE;
- return SUCCESS;
-}
-
-/* aghtmlstr:
- * Return true if s is an HTML string.
- * We assume s points to the datafield store[0] of a refstr.
- */
-int aghtmlstr(char *s)
-{
- refstr_t *key;
-
- if (s == NULL)
- return 0;
- key = (refstr_t *) (s - offsetof(refstr_t, store[0]));
- return (key->refcnt & HTML_BIT);
-}
-
-#ifdef DEBUG
-static int refstrprint(Dict_t * dict, void *ptr, void *user)
-{
- refstr_t *r;
-
- NOTUSED(dict);
- r = ptr;
- NOTUSED(user);
- write(2, r->s, strlen(r->s));
- write(2, "\n", 1);
- return 0;
-}
-
-void agrefstrdump(Agraph_t * g)
-{
- dtwalk(Refdict_default, refstrprint, 0);
-}
-#endif
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-/* requires flex (i.e. not lex) */
-%{
-#include <ctype.h>
-#include "grammar.h"
-#include "aghdr.h"
-#ifdef WIN32
-#include <io.h>
-#endif
-
-#define GRAPH_EOF_TOKEN '@' /* lex class must be defined below */
- /* this is a workaround for linux flex */
-static int line_num = 1;
-static int html_nest = 0; /* nesting level for html strings */
-static char* InputFile;
-static Agdisc_t *Disc;
-static void *Ifile;
-static int graphType;
-
- /* Reset line number */
-void agreadline(int n) { line_num = n; }
-
- /* (Re)set file:
- */
-void agsetfile(char* f) { InputFile = f; line_num = 1; }
-
-/* There is a hole here, because switching channels
- * requires pushing back whatever was previously read.
- * There probably is a right way of doing this.
- */
-void aglexinit(Agdisc_t *disc, void *ifile) { Disc = disc; Ifile = ifile; graphType = 0;}
-
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ((result = Disc->io->afread(Ifile, buf, max_size)) < 0) \
- YY_FATAL_ERROR( "input in flex scanner failed" )
-#endif
-
-/* buffer for arbitrary length strings (longer than BUFSIZ) */
-static char *Sbuf,*Sptr,*Send;
-static void beginstr(void) {
- if (Sbuf == NIL(char*)) {
- Sbuf = malloc(BUFSIZ);
- Send = Sbuf + BUFSIZ;
- }
- Sptr = Sbuf;
- *Sptr = 0;
-}
-
-static void addstr(char *src) {
- char c;
- if (Sptr > Sbuf) Sptr--;
- do {
- do {c = *Sptr++ = *src++;} while (c && (Sptr < Send));
- if (c) {
- long sz = Send - Sbuf;
- long off = Sptr - Sbuf;
- sz *= 2;
- Sbuf = (char*)realloc(Sbuf,sz);
- Send = Sbuf + sz;
- Sptr = Sbuf + off;
- }
- } while (c);
-}
-
-static void endstr(void) {
- yylval.str = (char*)agstrdup(Ag_G_global,Sbuf);
-}
-
-static void endstr_html(void) {
- yylval.str = (char*)agstrdup_html(Ag_G_global,Sbuf);
-}
-
-static void
-storeFileName (char* fname, int len)
-{
- static int cnt;
- static char* buf;
-
- if (len > cnt) {
- if (cnt) buf = (char*)realloc (buf, len+1);
- else buf = (char*)malloc (len+1);
- cnt = len;
- }
- strcpy (buf, fname);
- InputFile = buf;
-}
-
-/* ppDirective:
- * Process a possible preprocessor line directive.
- * yytext = #.*
- */
-static void ppDirective (void)
-{
- int r, cnt, lineno;
- char buf[2];
- char* s = yytext + 1; /* skip initial # */
-
- if (strncmp(s, "line", 4) == 0) s += 4;
- r = sscanf(s, "%d %1[\"]%n", &lineno, buf, &cnt);
- if (r > 0) { /* got line number */
- line_num = lineno - 1;
- if (r > 1) { /* saw quote */
- char* p = yytext + 1 + cnt;
- char* e = p;
- while (*e && (*e != '"')) e++;
- if (e != p) {
- *e = '\0';
- storeFileName (p, e-p);
- }
- }
- }
-}
-
-/* chkNum:
- * The regexp for NUMBER allows a terminating letter.
- * This way we can catch a number immediately followed by a name
- * and report this to the user.
- */
-static int chkNum(void) {
- unsigned char c = (unsigned char)yytext[yyleng-1]; /* last character */
- if (!isdigit(c) && (c != '.')) { /* c is letter */
- char buf[BUFSIZ];
- sprintf(buf,"badly formed number '%s' in line %d\n",yytext,line_num);
- strcat (buf, "Splits into two name tokens");
- agerror(AGERROR_SYNTAX,buf);
- return 1;
- }
- else return 0;
-}
-
-/* The LETTER class below consists of ascii letters, underscore, all non-ascii
- * characters. This allows identifiers to have characters from any
- * character set independent of locale. The downside is that, for certain
- * character sets, non-letter and, in fact, undefined characters will be
- * accepted. This is not likely and, from dot's stand, shouldn't do any
- * harm. (Presumably undefined characters will be ignored in display.) And,
- * it allows a greater wealth of names. */
-%}
-GRAPH_EOF_TOKEN [@]
-LETTER [A-Za-z_\200-\377]
-DIGIT [0-9]
-NAME {LETTER}({LETTER}|{DIGIT})*
-NUMBER [-]?(({DIGIT}+(\.{DIGIT}*)?)|(\.{DIGIT}+)){LETTER}?
-ID ({NAME}|{NUMBER})
-%x comment
-%x qstring
-%x hstring
-%%
-{GRAPH_EOF_TOKEN} return(EOF);
-<INITIAL,comment,qstring>\n line_num++;
-"/*" BEGIN(comment);
-<comment>[^*\n]* /* eat anything not a '*' */
-<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
-<comment>"*"+"/" BEGIN(INITIAL);
-"//".* /* ignore C++-style comments */
-^"#".* ppDirective ();
-"#".* /* ignore shell-like comments */
-[\000-\040\177] /* ignore whitespace */
-"node" return(T_node); /* see tokens in agcanonstr */
-"edge" return(T_edge);
-"graph" if (!graphType) graphType = T_graph; return(T_graph);
-"digraph" if (!graphType) graphType = T_digraph; return(T_digraph);
-"strict" return(T_strict);
-"subgraph" return(T_subgraph);
-"->" if (graphType == T_digraph) return(T_edgeop); else return ('-');
-"--" if (graphType == T_graph) return(T_edgeop); else return ('-');
-{NAME} { yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
-{NUMBER} { if (chkNum()) yyless(yyleng-1); yylval.str = (char*)agstrdup(Ag_G_global,yytext); return(T_atom); }
-["] BEGIN(qstring); beginstr();
-<qstring>["] BEGIN(INITIAL); endstr(); return (T_qatom);
-<qstring>[\\]["] addstr ("\"");
-<qstring>[\\][\n] line_num++; /* ignore escaped newlines */
-<qstring>([^"\\]*|[\\].) addstr(yytext);
-[<] BEGIN(hstring); html_nest = 1; beginstr();
-<hstring>[>] html_nest--; if (html_nest) addstr(yytext); else {BEGIN(INITIAL); endstr_html(); return (T_qatom);}
-<hstring>[<] html_nest++; addstr(yytext);
-<hstring>[\n] addstr(yytext); line_num++; /* add newlines */
-<hstring>([^><]*) addstr(yytext);
-. return (yytext[0]);
-%%
-void yyerror(char *str)
-{
- char buf[BUFSIZ];
- if (InputFile)
- sprintf(buf,"%s:%d: %s in line %d near '%s'\n",InputFile, line_num,
- str,line_num,yytext);
- else
- sprintf(buf," %s in line %d near '%s'\n", str,line_num,yytext);
- agerror(AGERROR_SYNTAX,buf);
-}
-/* must be here to see flex's macro defns */
-void aglexeof() { unput(GRAPH_EOF_TOKEN); }
-
-#ifndef YY_CALL_ONLY_ARG
-# define YY_CALL_ONLY_ARG void
-#endif
-
-int yywrap(YY_CALL_ONLY_ARG)
-{
- return 1;
-}
-
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-static Agraph_t *agfindsubg_by_id(Agraph_t * g, unsigned long id)
-{
- Agraph_t template;
-
- agdtdisc(g, g->g_dict, &Ag_obj_id_disc);
- AGID(&template) = id;
- return (Agraph_t *) dtsearch(g->g_dict, &template);
-}
-
-static Agraph_t *localsubg(Agraph_t * g, unsigned long id)
-{
- Agraph_t *subg;
-
- subg = agfindsubg_by_id(g, id);
- if (subg)
- return subg;
-
- subg = agalloc(g, sizeof(Agraph_t));
- subg->clos = g->clos;
- subg->desc = g->desc;
- subg->desc.maingraph = FALSE;
- subg->desc.flatlock = FALSE;
- subg->parent = g;
- subg->root = g->root;
- AGID(subg) = id;
- return agopen1(subg);
-}
-
-Agraph_t *agidsubg(Agraph_t * g, unsigned long id, int cflag)
-{
- Agraph_t *subg;
- subg = agfindsubg_by_id(g, id);
- if ((subg == NILgraph) && cflag && agallocid(g, AGRAPH, id))
- subg = localsubg(g, id);
- return subg;
-}
-
-Agraph_t *agsubg(Agraph_t * g, char *name, int cflag)
-{
- unsigned long id;
- Agraph_t *subg;
-
- if (name && agmapnametoid(g, AGRAPH, name, &id, FALSE)) {
- /* might already exist */
- if ((subg = agfindsubg_by_id(g, id)))
- return subg;
- }
-
- if (cflag && agmapnametoid(g, AGRAPH, name, &id, TRUE)) /* reserve id */
- return localsubg(g, id);
-
- return NILgraph;
-}
-
-Agraph_t *agfstsubg(Agraph_t * g)
-{
- return (Agraph_t *) dtfirst(g->g_dict);
-}
-
-Agraph_t *agnxtsubg(Agraph_t * subg)
-{
- Agraph_t *g;
-
- g = agparent(subg);
- return (Agraph_t *) dtnext(g->g_dict, subg);
-}
-
-Agraph_t *agparent(Agraph_t * g)
-{
- return g->parent;
-}
-
-Agraph_t *agroot(Agraph_t * g)
-{
- return g->root;
-}
-
-/* this function is only responsible for deleting the entry
- * in the parent's subg dict. the rest is done in agclose().
- */
-long agdelsubg(Agraph_t * g, Agraph_t * subg)
-{
- return (long) dtdelete(g->g_dict, subg);
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include <assert.h>
-#include <signal.h>
-#include <stdio.h>
-#include "agraph.h"
-
-#define NILgraph NIL(Agraph_t*)
-#define NILnode NIL(Agnode_t*)
-#define NILedge NIL(Agedge_t*)
-#define NILsym NIL(Agsym_t*)
-#define NILstr NIL(char*)
-
-main()
-{
- Agraph_t *g;
- Agnode_t *n;
- Agedge_t *e;
- Agsym_t *sym;
- char *val;
-
- while (g = agread(stdin, NIL(Agdisc_t *))) {
- for (n = agfstnode(g); n; n = agnxtnode(n)) {
- /*fprintf(stderr,"%s\n", agnameof(n)); */
- for (sym = agnxtattr(g, AGNODE, 0); sym;
- sym = agnxtattr(g, AGNODE, sym)) {
- val = agxget(n, sym);
- /*fprintf(stderr,"\t%s=%s\n",sym->name,val); */
- }
- }
- agwrite(g, stdout);
- }
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#include "aghdr.h"
-
-static Agraph_t *Ag_dictop_G;
-
-/* only indirect call through dtopen() is expected */
-void *agdictobjmem(Dict_t * dict, Void_t * p, size_t size, Dtdisc_t * disc)
-{
- Agraph_t *g;
-
- NOTUSED(dict);
- NOTUSED(disc);
- g = Ag_dictop_G;
- if (g) {
- if (p)
- agfree(g, p);
- else
- return agalloc(g, size);
- } else {
- if (p)
- free(p);
- else
- return malloc(size);
- }
- return NIL(void *);
-}
-
-void agdictobjfree(Dict_t * dict, Void_t * p, Dtdisc_t * disc)
-{
- Agraph_t *g;
-
- NOTUSED(dict);
- NOTUSED(disc);
- g = Ag_dictop_G;
- if (g)
- agfree(g, p);
- else
- free(p);
-}
-
-Dict_t *agdtopen(Agraph_t * g, Dtdisc_t * disc, Dtmethod_t * method)
-{
- Dtmemory_f memf;
- Dict_t *d;
-
- memf = disc->memoryf;
- disc->memoryf = agdictobjmem;
- Ag_dictop_G = g;
- d = dtopen(disc, method);
- disc->memoryf = memf;
- return d;
-}
-
-long agdtdelete(Agraph_t * g, Dict_t * dict, void *obj)
-{
- Ag_dictop_G = g;
- return (long) dtdelete(dict, obj);
-}
-
-int agobjfinalize(Void_t * obj)
-{
- agfree(Ag_dictop_G, obj);
- return 0;
-}
-
-void agdtclose(Agraph_t * g, Dict_t * dict)
-{
- Dtmemory_f memf;
- Dtdisc_t *disc;
-
- disc = dtdisc(dict, NIL(Dtdisc_t *), 0);
- memf = disc->memoryf;
- disc->memoryf = agdictobjmem;
- Ag_dictop_G = g;
- if (dtclose(dict))
- abort();
- disc->memoryf = memf;
-}
-
-void agdtdisc(Agraph_t * g, Dict_t * dict, Dtdisc_t * disc)
-{
- if (disc && (dtdisc(dict, NIL(Dtdisc_t *), 0) != disc)) {
- agflatten(g, FALSE);
- dtdisc(dict, disc, 0);
- }
- /* else unchanged, disc is same as old disc */
-}
+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-
-#ifdef WIN32
-#include <compat.h>
-#endif
-#include <stdio.h> /* need sprintf() */
-#include <ctype.h>
-#include "aghdr.h"
-
-#define EMPTY(s) ((s == 0) || (s)[0] == '\0')
-#define MAX(a,b) ((a)>(b)?(a):(b))
-
-typedef void iochan_t;
-
-static void ioput(Agraph_t * g, iochan_t * ofile, char *str)
-{
- AGDISC(g, io)->putstr(ofile, str);
-}
-
-static void write_body(Agraph_t * g, iochan_t * ofile);
-static int Level;
-static Agsym_t *Tailport, *Headport;
-
-static void indent(Agraph_t * g, iochan_t * ofile)
-{
- int i;
- for (i = Level; i > 0; i--)
- ioput(g, ofile, "\t");
-}
-
-#ifndef HAVE_STRCASECMP
-
-#include <string.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
- while ((*s1 != '\0')
- && (tolower(*(unsigned char *) s1) ==
- tolower(*(unsigned char *) s2))) {
- s1++;
- s2++;
- }
-
- return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
-}
-
-#endif /* HAVE_STRCASECMP */
-
-/* _agcanonstr:
- * Canonicalize ordinary strings.
- * Assumes buf is large enough to hold output.
- */
-static char*
-_agcanonstr(char *arg, char *buf)
-{
- char *s, *p;
- unsigned char uc;
- int cnt = 0;
- int needs_quotes = FALSE;
- int maybe_num;
- static const char *tokenlist[] /* must agree with scan.l */
- = { "node", "edge", "strict", "graph", "digraph", "subgraph",
- NIL(char *) };
- const char **tok;
-
- if (EMPTY(arg))
- return "\"\"";
- s = arg;
- p = buf;
- *p++ = '\"';
- uc = *(unsigned char *) s++;
- maybe_num = (isdigit(uc) || (uc == '.'));
- while (uc) {
- if (uc == '\"') {
- *p++ = '\\';
- needs_quotes = TRUE;
- } else {
- if (!ISALNUM(uc))
- needs_quotes = TRUE;
- else if (maybe_num && (!isdigit(uc) && (uc != '.')))
- needs_quotes = TRUE;
- }
- *p++ = (char) uc;
- uc = *(unsigned char *) s++;
- cnt++;
- if (cnt >= MAX_OUTPUTLINE) {
- *p++ = '\\';
- *p++ = '\n';
- needs_quotes = TRUE;
- cnt = 0;
- }
- }
- *p++ = '\"';
- *p = '\0';
- if (needs_quotes)
- return buf;
-
- /* Use quotes to protect tokens (example, a node named "node") */
- /* It would be great if it were easier to use flex here. */
- for (tok = tokenlist; *tok; tok++)
- if (!strcasecmp(*tok, arg))
- return buf;
- return arg;
-}
-
-/* agcanonhtmlstr:
- * Canonicalize html strings.
- */
-static char *agcanonhtmlstr(char *arg, char *buf)
-{
- char *s, *p;
-
- s = arg;
- p = buf;
- *p++ = '<';
- while (*s)
- *p++ = *s++;
- *p++ = '>';
- *p = '\0';
- return buf;
-}
-
-/*
- * canonicalize a string for printing.
- * must agree with strings in scan.l
- * Unsafe if buffer is not large enough.
- */
-char*
-agcanonstr(char *arg, char *buf)
-{
- if (aghtmlstr(arg))
- return agcanonhtmlstr(arg, buf);
- else
- return _agcanonstr(arg, buf);
-}
-
-static char *getoutputbuffer(char *str)
-{
- static char *rv;
- static int len;
- int req;
-
- req = MAX(2 * strlen(str) + 2, BUFSIZ);
- if (req > len) {
- if (rv)
- rv = realloc(rv, req);
- else
- rv = malloc(req);
- len = req;
- }
- return rv;
-}
-
-/*
- * canonicalize a string for printing.
- * must agree with strings in scan.l
- */
-char*
-agcanonStr(char *str)
-{
- return agcanonstr(str, getoutputbuffer(str));
-}
-
-static void _write_canonstr(Agraph_t * g, iochan_t * ofile, char *str, int chk)
-{
- if (chk)
- str = agcanonStr(str);
- else
- str = _agcanonstr(str, getoutputbuffer(str));
- ioput(g, ofile, str);
-}
-
-static void write_canonstr(Agraph_t * g, iochan_t * ofile, char *str)
-{
- _write_canonstr(g, ofile, str, TRUE);
-}
-
-static void write_dict(Agraph_t * g, iochan_t * ofile, char *name,
- Dict_t * dict)
-{
- int cnt = 0;
- Dict_t *view;
- Agsym_t *sym, *psym;
-
- view = dtview(dict, NIL(Dict_t *));
- for (sym = (Agsym_t *) dtfirst(dict); sym;
- sym = (Agsym_t *) dtnext(dict, sym)) {
- if (EMPTY(sym->defval)) { /* try to skip empty str (default) */
- if (view == NIL(Dict_t *))
- continue; /* no parent */
- psym = (Agsym_t *) dtsearch(view, sym);
- assert(psym);
- if (EMPTY(psym->defval))
- continue; /* also empty in parent */
- }
- if (cnt++ == 0) {
- indent(g, ofile);
- ioput(g, ofile, name);
- ioput(g, ofile, " [");
- Level++;
- } else {
- ioput(g, ofile, ",\n");
- indent(g, ofile);
- }
- write_canonstr(g, ofile, sym->name);
- ioput(g, ofile, "=");
- write_canonstr(g, ofile, sym->defval);
- }
- if (cnt > 0) {
- Level--;
- if (cnt > 1) {
- ioput(g, ofile, "\n");
- indent(g, ofile);
- }
- ioput(g, ofile, "];\n");
- }
- dtview(dict, view); /* restore previous view */
-}
-
-static void write_dicts(Agraph_t * g, iochan_t * ofile)
-{
- Agdatadict_t *def;
- if ((def = agdatadict(g))) {
- write_dict(g, ofile, "graph", def->dict.g);
- write_dict(g, ofile, "node", def->dict.n);
- write_dict(g, ofile, "edge", def->dict.e);
- }
-}
-
-static void write_hdr(Agraph_t * g, iochan_t * ofile, int top)
-{
- char *name, *sep, *kind, *strict;
- int root = 0;
-
- strict = "";
- if (NOT(top) && agparent(g))
- kind = "sub";
- else {
- root = 1;
- if (g->desc.directed)
- kind = "di";
- else
- kind = "";
- if (agisstrict(g))
- strict = "strict ";
- Tailport = agattr(g, AGEDGE, TAIL_ID, NIL(char *));
- Headport = agattr(g, AGEDGE, HEAD_ID, NIL(char *));
- }
- name = agnameof(g);
- sep = " ";
- if (!name || name[0] == LOCALNAMEPREFIX)
- sep = name = "";
- indent(g, ofile);
- ioput(g, ofile, strict);
-
- /* output "<kind>graph" only for root graphs or graphs with names */
- if (*name || root) {
- ioput(g, ofile, kind);
- ioput(g, ofile, "graph ");
- }
- if (name[0])
- write_canonstr(g, ofile, name);
- ioput(g, ofile, sep);
- ioput(g, ofile, "{\n");
- Level++;
- write_dicts(g, ofile);
- AGATTRWF(g) = TRUE;
-}
-
-static void write_trl(Agraph_t * g, iochan_t * ofile)
-{
- NOTUSED(g);
- Level--;
- indent(g, ofile);
- ioput(g, ofile, "}\n");
-}
-
-static int irrelevant_subgraph(Agraph_t * g)
-{
- int i, n;
- Agattr_t *sdata, *pdata, *rdata;
- Agdatadict_t *dd;
-
- char *name;
-
- name = agnameof(g);
- if (name && name[0] != LOCALNAMEPREFIX)
- return FALSE;
- if ((sdata = agattrrec(g)) && (pdata = agattrrec(agparent(g)))) {
- rdata = agattrrec(agroot(g));
- n = dtsize(rdata->dict);
- for (i = 0; i < n; i++)
- if (sdata->str[i] && pdata->str[i]
- && strcmp(sdata->str[i], pdata->str[i]))
- return FALSE;
- }
- dd = agdatadict(g);
- if ((dtsize(dd->dict.n) > 0) || (dtsize(dd->dict.e) > 0))
- return FALSE;
- return TRUE;
-}
-
-static int node_in_subg(Agraph_t * g, Agnode_t * n)
-{
- Agraph_t *subg;
-
- for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
- if (irrelevant_subgraph(subg))
- continue;
- if (agsubnode(subg, n, FALSE))
- return TRUE;
- }
- return FALSE;
-}
-
-static int has_no_edges(Agnode_t * n)
-{
- return ((n->in == NIL(Agedge_t *)) && (n->out == NIL(Agedge_t *)));
-}
-
-static int has_no_predecessor_below(Agnode_t * n, unsigned long val)
-{
- Agedge_t *e;
-
- if (AGSEQ(n) < val)
- return FALSE;
- for (e = agfstin(n); e; e = agnxtin(e))
- if (AGSEQ(e->node) < val)
- return FALSE;
- return TRUE;
-}
-
-static int not_default_attrs(Agraph_t * g, Agnode_t * n)
-{
- Agattr_t *data;
- Agsym_t *sym;
-
- NOTUSED(g);
- if ((data = agattrrec(n))) {
- for (sym = (Agsym_t *) dtfirst(data->dict); sym;
- sym = (Agsym_t *) dtnext(data->dict, sym)) {
- if (data->str[sym->id] != sym->defval)
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static void write_subgs(Agraph_t * g, iochan_t * ofile)
-{
- Agraph_t *subg;
-
- for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
- if (irrelevant_subgraph(subg))
- continue;
- write_hdr(subg, ofile, FALSE);
- write_body(subg, ofile);
- write_trl(subg, ofile);
- }
-}
-
-static int write_edge_name(Agedge_t * e, iochan_t * ofile, int terminate)
-{
- int rv;
- char *p;
- Agraph_t *g;
-
- p = agnameof(e);
- g = agraphof(e);
- if (NOT(EMPTY(p))) {
- ioput(g, ofile, " [key=");
- write_canonstr(g, ofile, p);
- if (terminate)
- ioput(g, ofile, "]");
- rv = TRUE;
- } else
- rv = FALSE;
- return rv;
-}
-
-
-static void write_nondefault_attrs(void *obj, iochan_t * ofile,
- Dict_t * defdict)
-{
- Agattr_t *data;
- Agsym_t *sym;
- Agraph_t *g;
- int cnt = 0;
-
- if ((AGTYPE(obj) == AGINEDGE) || (AGTYPE(obj) == AGOUTEDGE)) {
- if (write_edge_name(obj, ofile, FALSE))
- cnt++;
- }
- data = agattrrec(obj);
- g = agraphof(obj);
- if (data)
- for (sym = (Agsym_t *) dtfirst(defdict); sym;
- sym = (Agsym_t *) dtnext(defdict, sym)) {
- if ((AGTYPE(obj) == AGINEDGE) || (AGTYPE(obj) == AGOUTEDGE)) {
- if (Tailport && (sym->id == Tailport->id))
- continue;
- if (Headport && (sym->id == Headport->id))
- continue;
- }
- if (data->str[sym->id] != sym->defval) {
- if (cnt++ == 0) {
- indent(g, ofile);
- ioput(g, ofile, " [");
- Level++;
- } else {
- ioput(g, ofile, ",\n");
- indent(g, ofile);
- }
- write_canonstr(g, ofile, sym->name);
- ioput(g, ofile, "=");
- write_canonstr(g, ofile, data->str[sym->id]);
- }
- }
- if (cnt > 0) {
- ioput(g, ofile, "]");
- Level--;
- }
- AGATTRWF((Agobj_t *) obj) = TRUE;
-}
-
-static void write_nodename(Agnode_t * n, iochan_t * ofile)
-{
- char *name, buf[20];
- Agraph_t *g;
-
- name = agnameof(n);
- g = agraphof(n);
- if (name)
- write_canonstr(g, ofile, name);
- else {
- sprintf(buf, "_%ld_SUSPECT", AGID(n)); /* could be deadly wrong */
- ioput(g, ofile, buf);
- }
-}
-
-static int attrs_written(void *obj)
-{
- return (AGATTRWF((Agobj_t *) obj));
-}
-
-static void write_node(Agnode_t * n, iochan_t * ofile, Dict_t * d)
-{
- Agraph_t *g;
-
- g = agraphof(n);
- indent(g, ofile);
- write_nodename(n, ofile);
- if (NOT(attrs_written(n)))
- write_nondefault_attrs(n, ofile, d);
- ioput(g, ofile, ";\n");
-}
-
-/* node must be written if it wasn't already emitted because of
- * a subgraph or one of its predecessors, and if it is a singleton
- * or has non-default attributes.
- */
-static int write_node_test(Agraph_t * g, Agnode_t * n,
- unsigned long pred_id)
-{
- if (NOT(node_in_subg(g, n)) && has_no_predecessor_below(n, pred_id)) {
- if (has_no_edges(n) || not_default_attrs(g, n))
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-write_port(Agedge_t * e, iochan_t * ofile, Agsym_t * port)
-{
- char *val;
- Agraph_t *g;
-
- if (!port)
- return;
- g = agraphof(e);
- val = agxget(e, port);
- if (val[0] == '\0')
- return;
-
- ioput(g, ofile, ":");
- if (aghtmlstr(val))
- write_canonstr(g, ofile, val);
- else {
- char* s = strchr (val, ':');
- if (s) {
- *s = '\0';
- _write_canonstr(g, ofile, val, FALSE);
- ioput(g, ofile, ":");
- _write_canonstr(g, ofile, s+1, FALSE);
- *s = ':';
- }
- else {
- _write_canonstr(g, ofile, val, FALSE);
- }
- }
-}
-
-static int write_edge_test(Agraph_t * g, Agedge_t * e)
-{
- Agraph_t *subg;
-
- /* can use agedge() because we subverted the dict compar_f */
- for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
- if (irrelevant_subgraph(subg))
- continue;
- if (agsubedge(subg, e, FALSE))
- return FALSE;
- }
- return TRUE;
-}
-
-static void write_edge(Agedge_t * e, iochan_t * ofile, Dict_t * d)
-{
- Agnode_t *t, *h;
- Agraph_t *g;
-
- t = AGTAIL(e);
- h = AGHEAD(e);
- g = agraphof(t);
- indent(g, ofile);
- write_nodename(t, ofile);
- write_port(e, ofile, Tailport);
- ioput(g, ofile, (agisdirected(agraphof(t)) ? " -> " : " -- "));
- write_nodename(h, ofile);
- write_port(e, ofile, Headport);
- if (NOT(attrs_written(e)))
- write_nondefault_attrs(e, ofile, d);
- else
- write_edge_name(e, ofile, TRUE);
- ioput(g, ofile, ";\n");
-}
-
-static void write_body(Agraph_t * g, iochan_t * ofile)
-{
- Agnode_t *n;
- Agedge_t *e;
- Agdatadict_t *dd;
- /* int has_attr; */
-
- /* has_attr = (agattrrec(g) != NIL(Agattr_t*)); */
- write_subgs(g, ofile);
- dd = agdatadict(g);
- for (n = agfstnode(g); n; n = agnxtnode(n)) {
- if (write_node_test(g, n, AGSEQ(n)))
- write_node(n, ofile, dd->dict.n);
- for (e = agfstout(n); e; e = agnxtout(e)) {
- if (write_node_test(g, e->node, AGSEQ(n)))
- write_node(e->node, ofile, dd->dict.n);
- if (write_edge_test(g, e))
- write_edge(e, ofile, dd->dict.e);
- }
- }
-}
-
-static void set_attrwf(Agraph_t *g, int toplevel, int value)
-{
- Agraph_t *subg;
- Agnode_t *n;
- Agedge_t *e;
-
- AGATTRWF(g) = value;
- for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
- set_attrwf(subg, FALSE, value);
- }
- if (toplevel) {
- for (n = agfstnode(g); n; n = agnxtnode(n)) {
- AGATTRWF(n) = value;
- for (e = agfstout(n); e; e = agnxtout(e))
- AGATTRWF(e) = value;
- }
- }
-}
-
-int agwrite(Agraph_t * g, void *ofile)
-{
- set_attrwf(g,TRUE,FALSE);
- write_hdr(g, ofile, TRUE);
- write_body(g, ofile);
- write_trl(g, ofile);
- return AGDISC(g, io)->flush(ofile);
-}