Graphviz  2.39.20141212.0545
graphio.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 
15 #include "libgraph.h"
16 
17 typedef struct printdict_t {
19 } printdict_t;
20 
21 /*
22  * memgets - same api as gets
23  *
24  * gets one line at a time from a memory buffer and places it in a user buffer
25  * up to a maximum of n characters
26  *
27  * returns pointer to obtained line in user buffer, or
28  * returns NULL when last line read from memory buffer
29  */
30 static char *memgets(char *ubuf, int n, FILE * mbuf)
31 {
32  static char *mempos;
33  char *to, *clp; /* clp = current line pointer */
34  int i;
35 
36  if (!n) { /* a call with n==0 (from aglexinit) resets */
37  mempos = (char *) mbuf; /* cast from FILE* required by API */
38  }
39 
40  clp = to = ubuf;
41  for (i = 0; i < n - 1; i++) { /* leave room for terminator */
42  if (*mempos == '\0') {
43  if (i) { /* if mbuf doesn't end in \n, provide one */
44  *to++ = '\n';
45  } else { /* all done */
46  clp = NULL;
47  mempos = NULL;
48  }
49  break; /* last line or end-of-buffer */
50  }
51  if (*mempos == '\n') {
52  *to++ = *mempos++;
53  break; /* all done with this line */
54  }
55  *to++ = *mempos++; /* copy character */
56  }
57  *to++ = '\0'; /* place terminator in ubuf */
58  return clp;
59 }
60 
61 static Agraph_t*
62 finish (int rv, Agraph_t *g)
63 {
64  if (rv) {
65  if (g) agclose (g);
66  return NULL;
67  }
68  else
69  return g;
70 }
71 
72 Agraph_t *agread(FILE * fp)
73 {
74  int rv;
75  aglexinit(fp, NULL); /* use fgets from current io discipline */
76  rv = agparse();
77  return finish(rv, AG.parsed_g);
78 }
79 
80 Agraph_t *agmemread(char *cp)
81 {
82  int rv;
83  gets_f savefgets = AG.fgets;
84 
85  AG.fgets = memgets; /* memgets defined above */
86  /* cast cp into a file pointer */
87  aglexinit((FILE *) cp, NULL);
88  rv = agparse();
89  AG.fgets = savefgets;
90  return finish(rv, AG.parsed_g);
91 }
92 
93 Agraph_t *agread_usergets(FILE * fp, gets_f usergets)
94 {
95  int rv;
96  gets_f savefgets = AG.fgets;
97 
98  AG.fgets = usergets; /* usergets provided externally */
99  aglexinit(fp, NULL);
100  rv = agparse();
101  AG.fgets = savefgets;
102  return finish(rv, AG.parsed_g);
103 }
104 
105 static int
106 _is_number_char(char c)
107 {
108  return (isdigit(c) || (c == '.'));
109 }
110 
111 /* _agstrcanon:
112  * Canonicalize an ordinary string if necessary.
113  */
114 static char*
115 _agstrcanon (char* arg, char* buf)
116 {
117  char *s = arg;
118  unsigned char uc;
119  char *p = buf;
120  int cnt = 0, dotcnt = 0;
121  int has_special = FALSE;
122  int maybe_num;
123  int backslash_pending = FALSE;
124 
125  if (ISEMPTYSTR(arg))
126  return "\"\"";
127  *p++ = '\"';
128  uc = *(unsigned char *) s++;
129  maybe_num = _is_number_char(uc) || (uc == '-');
130  while (uc) {
131  if (uc == '\"') {
132  *p++ = '\\';
133  has_special = TRUE;
134  }
135  else if (maybe_num) {
136  if (uc == '-') {
137  if (cnt) {
138  maybe_num = FALSE;
139  has_special = TRUE;
140  }
141  }
142  else if (uc == '.') {
143  if (dotcnt++) {
144  maybe_num = FALSE;
145  has_special = TRUE;
146  }
147  }
148  else if (!isdigit(uc)) {
149  maybe_num = FALSE;
150  has_special = TRUE;
151  }
152  }
153  else if (!ISALNUM(uc))
154  has_special = TRUE;
155  *p++ = (char) uc;
156  uc = *(unsigned char *) s++;
157  cnt++;
158  if (uc && backslash_pending && !((_is_number_char(p[-1]) || isalpha(p[-1]) || (p[-1] == '\\')) && (_is_number_char(uc) || isalpha(uc)))) {
159  *p++ = '\\';
160  *p++ = '\n';
161  has_special = TRUE;
162  backslash_pending = FALSE;
163  } else if (uc && cnt % SMALLBUF == 0) {
164  if (!((_is_number_char(p[-1]) || isalpha(p[-1]) || (p[-1] == '\\')) && (_is_number_char(uc) || isalpha(uc)))) {
165  *p++ = '\\';
166  *p++ = '\n';
167  has_special = TRUE;
168  } else {
169  backslash_pending = TRUE;
170  }
171  }
172  }
173  *p++ = '\"';
174  *p = '\0';
175  if (has_special || ((cnt == 1) && ((*arg == '.') || (*arg == '-'))))
176  return buf;
177 
178  /* use quotes to protect tokens (example, a node named "node") */
179  if (agtoken(arg) >= 0)
180  return buf;
181  return arg;
182 }
183 
184 /* agstrcanon:
185  * handles both html and ordinary strings.
186  * canonicalize a string for printing.
187  * changes to the semantics of this function
188  * also involve the string scanner in lexer.c
189  * Unsafe if buf is not large enough.
190  */
191 char *agstrcanon(char *arg, char *buf)
192 {
193  char *s = arg;
194  char *p = buf;
195 
196  if (aghtmlstr(arg)) {
197  *p++ = '<';
198  while (*s)
199  *p++ = *s++;
200  *p++ = '>';
201  *p = '\0';
202  return buf;
203  }
204  else
205  return (_agstrcanon(arg, buf));
206 }
207 
209  char * (*myfgets) (char *s, int size, FILE *stream),
210  size_t (*myfwrite) (const void *ptr, size_t size, size_t nmemb, FILE *stream),
211  int (*myferror) (FILE *stream)
212 )
213 {
214  if (myfgets) AG.fgets = myfgets;
215  if (myfwrite) AG.fwrite = myfwrite;
216 #if defined(__SUNPRO_C) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__FreeBSD__)
217 #undef ferror
218 #endif
219  if (myferror) AG.ferror = myferror;
220 }
221 
222 
223 int agputs(const char *s, FILE *fp)
224 {
225  size_t len = strlen(s);
226 
227  if (AG.fwrite(s, sizeof(char), len, fp) != len) {
228  return EOF;
229  }
230  return +1;
231 }
232 
233 int agputc(int c, FILE *fp)
234 {
235  const char cc = c;
236 
237  if (AG.fwrite (&cc, sizeof(char), 1, fp) != 1) {
238  return EOF;
239  }
240  return c;
241 }
242 
243 static void tabover(FILE * fp, int tab)
244 {
245  while (tab--)
246  agputc('\t', fp);
247 }
248 
249 static char *getoutputbuffer(char *str)
250 {
251  static char *rv;
252  static int len;
253  int req;
254 
255  req = MAX(2 * strlen(str) + 2, BUFSIZ);
256  if (req > len) {
257  if (rv)
258  rv = (char*)realloc(rv, req);
259  else
260  rv = (char*)malloc(req);
261  len = req;
262  }
263  return rv;
264 }
265 
266 /* agcanonical:
267  * Safe version of agstrcanon.
268  */
269 char*
270 agcanonical(char *str)
271 {
272  return agstrcanon(str, getoutputbuffer(str));
273 }
274 
275 /* agcanon:
276  * Safe version of agstrcanon but using only double quotes.
277  * Any string can be used, but there is no check for html strings.
278  */
279 char*
280 agcanon(char *str)
281 {
282  return _agstrcanon(str, getoutputbuffer(str));
283 }
284 
285 static void write_dict(Agdict_t * dict, FILE * fp)
286 {
287  int i, cnt = 0;
288  Agsym_t *a;
289 
290  for (i = 0; i < dtsize(dict->dict); i++) {
291  a = dict->list[i];
292  if (ISEMPTYSTR(a->value) == FALSE) {
293  if (cnt++ == 0) {
294  agputc('\t', fp);
295  agputs(dict->name, fp);
296  agputs(" [", fp);
297  }
298  else {
299  agputs(", ", fp);
300  }
301  agputs(a->name, fp);
302  agputc('=', fp);
303  agputs(agcanonical(a->value), fp);
304  }
305  }
306  if (cnt > 0)
307  agputs("];\n", fp);
308 }
309 
310 static void write_diffattr(FILE * fp, int indent, void *obj, void *par,
311  Agdict_t * dict)
312 {
313  Agsym_t *a;
314  int i;
315  char *p, *q;
316  int cnt = 0;
317 
318  for (i = 0; i < dtsize(dict->dict); i++) {
319  a = dict->list[i];
320  if (a->printed == FALSE)
321  continue;
322  p = agxget(obj, a->index);
323  if (par)
324  q = agxget(par, a->index);
325  else
326  q = a->value;
327  if (strcmp(p, q)) {
328  if (cnt++ == 0) {
329  tabover(fp, indent);
330  agputs(dict->name, fp);
331  agputs(" [", fp);
332  } else {
333  agputs(",\n", fp);
334  tabover(fp, indent + 1);
335  }
336  agputs(agcanonical(a->name), fp);
337  agputc('=', fp);
338  agputs(agcanonical(p), fp);
339  }
340  }
341  if (cnt > 0)
342  agputs("];\n", fp);
343 }
344 
345 static void writeattr(FILE * fp, int *npp, char *name, char *val)
346 {
347  agputs(++(*npp) > 1 ? ", " : " [", fp);
348  agputs(agcanonical(name), fp);
349  agputc('=', fp);
350  agputs(agcanonical(val), fp);
351 }
352 
353 void agwrnode(Agraph_t * g, FILE * fp, Agnode_t * n, int full, int indent)
354 {
355  char *myval, *defval;
356  int i, didwrite = FALSE;
357  int nprint = 0;
358  Agdict_t *d = n->graph->univ->nodeattr;
359  Agsym_t *a;
360 
361  if (full) {
362  for (i = 0; i < dtsize(d->dict); i++) {
363  a = d->list[i];
364  if (a->printed == FALSE)
365  continue;
366  myval = agget(n, a->name);
367  if (g == n->graph)
368  defval = a->value;
369  else
370  defval = agget(g->proto->n, a->name);
371  if (strcmp(defval, myval)) {
372  if (didwrite == FALSE) {
373  tabover(fp, indent);
374  agputs(agcanonical(n->name), fp);
375  didwrite = TRUE;
376  }
377  writeattr(fp, &nprint, a->name, myval);
378  }
379  }
380  if (didwrite) {
381  agputs(nprint > 0 ? "];\n" : ";\n", fp);
382  return;
383  }
384  }
385  if ((agfstout(g, n) == NULL) && (agfstin(g, n) == NULL)) {
386  tabover(fp, indent);
387  agputs(agcanonical(n->name), fp);
388  agputs(";\n", fp);
389  }
390 }
391 
392 /* writenodeandport:
393  */
394 static void writenodeandport(FILE * fp, char *node, char *port)
395 {
396  char *ss;
397  agputs(agcanonical(node), fp); /* slimey i know */
398  if (port && *port) {
399  if (aghtmlstr(port)) {
400  agputc(':', fp);
401  agputs(agstrcanon(port, getoutputbuffer(port)), fp);
402  }
403  else {
404  ss = strchr (port, ':');
405  if (ss) {
406  *ss = '\0';
407  agputc(':', fp);
408  agputs(_agstrcanon(port, getoutputbuffer(port)), fp);
409  agputc(':', fp);
410  agputs(_agstrcanon(ss+1, getoutputbuffer(ss+1)), fp);
411  *ss = ':';
412  }
413  else {
414  agputc(':', fp);
415  agputs(_agstrcanon(port, getoutputbuffer(port)), fp);
416  }
417  }
418  }
419 }
420 
421 void agwredge(Agraph_t * g, FILE * fp, Agedge_t * e, int list_all)
422 {
423  char *myval, *defval, *tport, *hport;
424  int i, nprint = 0;
425  Agdict_t *d = e->tail->graph->univ->edgeattr;
426  Agsym_t *a;
427 
428  if (e->attr) {
429  tport = e->attr[TAILX];
430  hport = e->attr[HEADX];
431  }
432  else tport = hport = "";
433  writenodeandport(fp, e->tail->name, tport);
434  agputs(((g->kind & AGFLAG_DIRECTED) ? " -> " : " -- "), fp);
435  writenodeandport(fp, e->head->name, hport);
436  if (list_all) {
437  for (i = 0; i < dtsize(d->dict); i++) {
438  a = d->list[i];
439  if ((a->printed == FALSE)
440  || ((i == KEYX) && (e->printkey != MUSTPRINT)))
441  continue;
442  myval = agget(e, a->name);
443  if (g == g->root)
444  defval = a->value;
445  else
446  defval = agget(g->proto->e, a->name);
447  if (strcmp(defval, myval))
448  writeattr(fp, &nprint, a->name, myval);
449  }
450  }
451  agputs(nprint > 0 ? "];\n" : ";\n", fp);
452 }
453 
455  offsetof(Agedge_t, id),
456  sizeof(int),
457  -1,
458  NIL(Dtmake_f),
459  NIL(Dtfree_f),
460  (Dtcompar_f) agcmpid,
461  NIL(Dthash_f),
462  NIL(Dtmemory_f),
463  NIL(Dtevent_f)
464 };
465 static void
466 write_subg(Agraph_t * g, FILE * fp, Agraph_t * par, int indent,
467  printdict_t * state)
468 {
469  Agraph_t *subg, *meta;
470  Agnode_t *n, *pn;
471  Agedge_t *e, *pe;
472  Dict_t *save_e, *save_n;
473 
474  if (indent) {
475  tabover(fp, indent++);
476  if (dtsearch(state->subgleft, g->meta_node)) {
477  if (strncmp(g->name, "_anonymous", 10)) {
478  agputs("subgraph ", fp);
479  agputs(agcanonical(g->name), fp);
480  agputs(" {\n", fp);
481  }
482  else {
483  agputs("{\n", fp); /* no name printed for anonymous subg */
484  }
485  write_diffattr(fp, indent, g, par, g->univ->globattr);
486  /* The root node and edge environment use the dictionaries,
487  * not the proto node or edge, so the next level down must
488  * record differences with the dictionaries.
489  */
490  if (par == g->root) {
491  pn = NULL;
492  pe = NULL;
493  } else {
494  pn = par->proto->n;
495  pe = par->proto->e;
496  }
497  write_diffattr(fp, indent, g->proto->n, pn, g->univ->nodeattr);
498  write_diffattr(fp, indent, g->proto->e, pe, g->univ->edgeattr);
499  dtdelete(state->subgleft, g->meta_node);
500  } else {
501  agputs("subgraph ", fp);
502  agputs(agcanonical(g->name), fp);
503  agputs(";\n", fp);
504  return;
505  }
506  } else
507  write_diffattr(fp, ++indent, g, NULL, g->univ->globattr);
508 
509  save_n = state->n_insubg;
510  save_e = state->e_insubg;
511  meta = g->meta_node->graph;
512  state->n_insubg = dtopen(&agNamedisc, Dttree);
513  state->e_insubg = dtopen(&agOutdisc, Dttree);
514  for (e = agfstout(meta, g->meta_node); e; e = agnxtout(meta, e)) {
515  subg = agusergraph(e->head);
516  write_subg(subg, fp, g, indent, state);
517  }
518  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
519  if (dtsearch(state->nodesleft, n)) {
520  agwrnode(g, fp, n, TRUE, indent);
521  dtdelete(state->nodesleft, n);
522  } else {
523  if (dtsearch(state->n_insubg, n) == NULL) {
524  agwrnode(g, fp, n, FALSE, indent);
525  }
526  }
527  dtinsert(save_n, n);
528  }
529 
530  dtdisc(g->outedges, &agEdgedisc, 0); /* sort by id */
531  for (e = (Agedge_t *) dtfirst(g->outedges); e;
532  e = (Agedge_t *) dtnext(g->outedges, e)) {
533  if (dtsearch(state->edgesleft, e)) {
534  tabover(fp, indent);
535  agwredge(g, fp, e, TRUE);
536  dtdelete(state->edgesleft, e);
537  } else {
538  if (dtsearch(state->e_insubg, e) == NULL) {
539  tabover(fp, indent);
540  agwredge(g, fp, e, FALSE);
541  }
542  }
543  dtinsert(save_e, e);
544  }
545  dtdisc(g->outedges, &agOutdisc, 0); /* sort by name */
546  dtclose(state->n_insubg);
547  state->n_insubg = save_n;
548  dtclose(state->e_insubg);
549  state->e_insubg = save_e;
550 
551  if (indent > 1) {
552  tabover(fp, indent - 1);
553  agputs("}\n", fp);
554  }
555 }
556 
557 static Dict_t *Copy;
558 static int copydictf(Dict_t * d, void *a, void *ignored)
559 {
560  dtinsert(Copy, (Agsym_t *) a);
561  return 0;
562 }
563 
564 static void copydict(Dict_t * from, Dict_t * to)
565 {
566  Copy = to;
567  dtwalk(from, copydictf, 0);
568 }
569 
570 static printdict_t *new_printdict_t(Agraph_t * g)
571 {
572  printdict_t *rv = NEW(printdict_t);
574  copydict(g->nodes, rv->nodesleft);
575  rv->edgesleft = dtopen(&agEdgedisc, Dttree);
576  copydict(g->outedges, rv->edgesleft);
577  rv->n_insubg = dtopen(&agNodedisc, Dttree);
578  rv->e_insubg = dtopen(&agOutdisc, Dttree);
579  rv->subgleft = dtopen(&agNodedisc, Dttree);
580  copydict(g->meta_node->graph->nodes, rv->subgleft);
581  return rv;
582 }
583 
584 static void free_printdict_t(printdict_t * dict)
585 {
586  dtclose(dict->nodesleft);
587  dtclose(dict->n_insubg);
588  dtclose(dict->edgesleft);
589  dtclose(dict->e_insubg);
590  dtclose(dict->subgleft);
591  free(dict);
592 }
593 
594 #ifdef ferror
595 /* if ferror is a macro (__SUNPRO_C __CYGWIN__ __MINGW32__ __FreeBSD__ and poss others)
596  * then wrap it in a function */
597 static int agferror(FILE *stream)
598 {
599  return ferror(stream);
600 }
601 #endif
602 
603 
604 int agwrite(Agraph_t * g, FILE * fp)
605 {
606  printdict_t *p;
607 
608  if (AG.fwrite == NULL) {
609  AG.fwrite = fwrite; /* init to system version of fwrite() */
610  }
611  if (AG.ferror == NULL) {
612 #ifdef ferror
613 #undef ferror
614  /* if ferror is a macro, then use our wrapper function, but
615  * undef the macro first so it doesn't subst in "AG.ferror" */
616  AG.ferror = agferror; /* init to ferror macro wrapper function */
617 #else
618  AG.ferror = ferror; /* init to system version of ferror() */
619 #endif
620  }
621 
622  /* write the graph header */
623  agputs((AG_IS_STRICT(g)) ? "strict " : "", fp);
624  agputs((AG_IS_DIRECTED(g)) ? "digraph" : "graph", fp);
625  if (strncmp(g->name, "_anonymous", 10)) {
626  agputc(' ', fp);
627  agputs(agcanonical(g->name), fp);
628  }
629  agputs(" {\n", fp);
630 
631  /* write the top level attribute defs */
632  write_dict(g->univ->globattr, fp);
633  write_dict(g->univ->nodeattr, fp);
634  write_dict(g->univ->edgeattr, fp);
635 
636  /* write the graph contents */
637  p = new_printdict_t(g);
638  write_subg(g, fp, (Agraph_t *) 0, 0, p);
639  agputs("}\n", fp);
640  free_printdict_t(p);
641  return AG.ferror(fp);
642 }
char * agstrcanon(char *arg, char *buf)
Definition: graphio.c:191
#define offsetof(typ, fld)
Definition: grid.c:98
int dtsize(Dt_t *dt)
Definition: dtsize.c:20
Definition: types.h:68
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:147
Agraph_t * agread_usergets(FILE *fp, gets_f usergets)
Definition: graphio.c:93
Agnode_t * n
Definition: graph.h:120
Dict_t * outedges
Definition: graph.h:68
int kind
Definition: graph.h:62
char * name
Definition: graph.h:81
size_t(* fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream)
Definition: libgraph.h:130
EXTERN struct AG_s AG
void agwredge(Agraph_t *g, FILE *fp, Agedge_t *e, int list_all)
Definition: graphio.c:421
char * agxget(void *obj, int index)
Definition: attribs.c:366
#define SMALLBUF
Definition: const.h:17
Dict_t * nodes
Definition: graph.h:68
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:163
Agnode_t * head
Definition: graph.h:93
Dict_t * n_insubg
Definition: graphio.c:18
Dtdisc_t agOutdisc
Definition: graph.c:58
#define dtdelete(d, o)
Definition: cdt.h:313
Definition: cdt.h:95
int agputc(int c, FILE *fp)
Definition: graphio.c:233
int index
Definition: graph.h:108
#define dtfirst(d)
Definition: cdt.h:303
Definition: graph.h:87
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition: edge.c:172
void agclose(Agraph_t *g)
Definition: graph.c:343
Agraph_t * graph
Definition: graph.h:83
int agputs(const char *s, FILE *fp)
Definition: graphio.c:223
Agdict_t * nodeattr
Definition: graph.h:100
#define AG_IS_STRICT(g)
Definition: graph.h:56
char *(* gets_f)(char *ubuf, int n, FILE *fp)
Definition: graph.h:43
Definition: graph.h:75
Agraph_t * agmemread(char *cp)
Definition: graphio.c:80
Dict_t * dict
Definition: graph.h:115
#define AG_IS_DIRECTED(g)
Definition: graph.h:55
Dict_t * e_insubg
Definition: graphio.c:18
char * malloc()
Dtdisc_t * dtdisc(Dt_t *dt, Dtdisc_t *disc, int type)
Definition: dtdisc.c:33
char * value
Definition: graph.h:107
Dtdisc_t agEdgedisc
Definition: graphio.c:454
#define NIL(t)
Definition: dthdr.h:20
void free()
int i
Definition: gvdevice.c:448
#define dtsearch(d, o)
Definition: cdt.h:309
char * realloc()
int dtwalk(reg Dt_t *dt, int(*userf)(), Void_t *data)
Definition: dtwalk.c:12
Definition: graph.h:60
#define TRUE
Definition: logic.h:42
Dict_t * subgleft
Definition: graphio.c:18
char * name
Definition: graph.h:107
char * agcanon(char *str)
Definition: graphio.c:280
#define AGFLAG_DIRECTED
Definition: graph.h:45
#define dtnext(d, o)
Definition: cdt.h:304
Agproto_t * proto
Definition: graph.h:71
char *(* fgets)(char *s, int size, FILE *stream)
Definition: libgraph.h:129
char ** attr
Definition: graph.h:91
#define HEADX
Definition: libgraph.h:120
int agparse(void)
char * agcanonical(char *str)
Definition: graphio.c:270
char * agget(void *obj, char *attr)
Definition: attribs.c:345
Agedge_t * e
Definition: graph.h:121
int agcmpid(Dt_t *dict, int *id0, int *id1, Dtdisc_t *disc)
Definition: graph.c:70
Agraph_t * root
Definition: graph.h:69
void aglexinit(FILE *fp, gets_f mygets)
Definition: lexer.c:74
char * name
Definition: graph.h:66
Agnode_t * agfstnode(Agraph_t *)
Definition: node.c:88
#define dtinsert(d, o)
Definition: cdt.h:311
#define MUSTPRINT
Definition: libgraph.h:102
Agdata_t * univ
Definition: graph.h:67
unsigned char printed
Definition: graph.h:109
int printkey
Definition: graph.h:89
void agsetiodisc(char *(*myfgets)(char *s, int size, FILE *stream), size_t(*myfwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream), int(*myferror)(FILE *stream))
Definition: graphio.c:208
Agdict_t * globattr
Definition: graph.h:102
Agsym_t ** list
Definition: graph.h:116
#define NULL
Definition: logic.h:50
#define FALSE
Definition: logic.h:39
Agraph_t * parsed_g
Definition: libgraph.h:124
#define TAILX
Definition: libgraph.h:119
#define MAX(a, b)
Definition: arith.h:43
Dtmethod_t * Dttree
Agnode_t * agnxtnode(Agraph_t *, Agnode_t *)
Definition: node.c:93
Definition: graph.h:106
Agraph_t * agusergraph(Agnode_t *n)
Definition: graph.c:279
Agnode_t * node(Agraph_t *g, char *name)
Definition: gv.cpp:103
#define KEYX
Definition: libgraph.h:118
Dt_t * dtopen(Dtdisc_t *disc, Dtmethod_t *meth)
Definition: dtopen.c:12
#define ISALNUM(c)
Definition: libgraph.h:98
Dtdisc_t agNodedisc
Definition: graph.c:34
char * name
Definition: graph.h:114
struct printdict_t printdict_t
Agnode_t * tail
Definition: graph.h:93
int aghtmlstr(char *s)
Definition: refstr.c:143
Definition: cdt.h:120
#define ISEMPTYSTR(s)
Definition: libgraph.h:104
Dict_t * edgesleft
Definition: graphio.c:18
int(* ferror)(FILE *stream)
Definition: libgraph.h:131
agxbuf * str
Definition: htmlparse.c:85
Agnode_t * meta_node
Definition: graph.h:70
int dtclose(reg Dt_t *dt)
Definition: dtclose.c:8
Dict_t * nodesleft
Definition: graphio.c:18
void agwrnode(Agraph_t *g, FILE *fp, Agnode_t *n, int full, int indent)
Definition: graphio.c:353
Agdict_t * edgeattr
Definition: graph.h:101
int agwrite(Agraph_t *g, FILE *fp)
Definition: graphio.c:604
int agtoken(char *p)
Definition: lexer.c:360
#define NEW(t)
Definition: memory.h:35
Dtdisc_t agNamedisc
Definition: graph.c:22
Agraph_t * agread(FILE *fp)
Definition: graphio.c:72