Graphviz  2.41.20170921.2350
gvrender_core_json.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2015 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 #include "config.h"
15 
16 #ifdef _WIN32
17 #include <io.h>
18 #include "compat.h"
19 #endif
20 
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 
26 #include "macros.h"
27 #include "const.h"
28 #include "xdot.h"
29 
30 #include "gvplugin_render.h"
31 #include "gvplugin_device.h"
32 #include "agxbuf.h"
33 #include "utils.h"
34 #include "gvc.h"
35 #include "gvio.h"
36 #include "gvcint.h"
37 
38 typedef enum {
43 } format_type;
44 
45 typedef struct {
46  int Level;
47  boolean isLatin;
48  boolean doXDot;
50 } state_t;
51 
52 typedef struct {
54  int id;
55 } gvid_t;
56 
57 #define ID "id"
58 #define ND_gid(n) (((gvid_t*)aggetrec(n, ID, FALSE))->id)
59 #define ED_gid(n) (((gvid_t*)aggetrec(n, ID, FALSE))->id)
60 #define GD_gid(n) (((gvid_t*)aggetrec(n, ID, FALSE))->id)
61 
62 #define IS_CLUSTER(s) (!strncmp(agnameof(s), "cluster", 7))
63 
64 static void json_begin_graph(GVJ_t *job)
65 {
66  if (job->render.id == FORMAT_JSON) {
67  GVC_t* gvc = gvCloneGVC (job->gvc);
68  graph_t *g = job->obj->u.g;
69  gvRender (gvc, g, "xdot", NULL);
70  gvFreeCloneGVC (gvc);
71  }
72  else if (job->render.id == FORMAT_JSON0) {
73  attach_attrs(job->gvc->g);
74  }
75 }
76 
77 #define LOCALNAMEPREFIX '%'
78 
79 /* stoj:
80  * Convert dot string to a valid json string embedded in double quotes.
81  */
82 static char* stoj (char* ins, state_t* sp)
83 {
84  char* s;
85  char* input;
86  static agxbuf xb;
87  unsigned char c;
88 
89  if (sp->isLatin)
90  input = latin1ToUTF8 (ins);
91  else
92  input = ins;
93 
94  if (xb.buf == NULL)
95  agxbinit(&xb, BUFSIZ, NULL);
96  for (s = input; (c = *s); s++) {
97  switch (c) {
98  case '"' :
99  agxbput(&xb, "\\\"");
100  break;
101  case '\\' :
102  agxbput(&xb, "\\\\");
103  break;
104  case '/' :
105  agxbput(&xb, "\\/");
106  break;
107  case '\b' :
108  agxbput(&xb, "\\b");
109  break;
110  case '\f' :
111  agxbput(&xb, "\\f");
112  break;
113  case '\n' :
114  agxbput(&xb, "\\n");
115  break;
116  case '\r' :
117  agxbput(&xb, "\\r");
118  break;
119  case '\t' :
120  agxbput(&xb, "\\t");
121  break;
122  default :
123  agxbputc(&xb, c);
124  break;
125  }
126  }
127  s = agxbuse(&xb);
128 
129  if (sp->isLatin)
130  free (input);
131  return s;
132 }
133 
134 static void indent(GVJ_t * job, int level)
135 {
136  int i;
137  for (i = level; i > 0; i--)
138  gvputs(job, " ");
139 }
140 
141 static void set_attrwf(Agraph_t * g, int toplevel, int value)
142 {
143  Agraph_t *subg;
144  Agnode_t *n;
145  Agedge_t *e;
146 
147  AGATTRWF(g) = value;
148  for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
149  set_attrwf(subg, FALSE, value);
150  }
151  if (toplevel) {
152  for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
153  AGATTRWF(n) = value;
154  for (e = agfstout(g, n); e; e = agnxtout(g, e))
155  AGATTRWF(e) = value;
156  }
157  }
158 }
159 
160 static void write_polyline (GVJ_t * job, xdot_polyline* polyline)
161 {
162  int i;
163  int cnt = polyline->cnt;
164  xdot_point* pts = polyline->pts;
165 
166  gvprintf(job, "\"points\": [");
167  for (i = 0; i < cnt; i++) {
168  if (i > 0) gvprintf(job, ",");
169  gvprintf(job, "[%.03f,%.03f]", pts[i].x, pts[i].y);
170  }
171  gvprintf(job, "]\n");
172 }
173 
174 static void write_stops (GVJ_t * job, int n_stops, xdot_color_stop* stp, state_t* sp)
175 {
176  int i;
177 
178  gvprintf(job, "\"stops\": [");
179  for (i = 0; i < n_stops; i++) {
180  if (i > 0) gvprintf(job, ",");
181  gvprintf(job, "{\"frac\": %.03f, \"color\": \"%s\"}",
182  stp[i].frac, stoj(stp[i].color, sp));
183  }
184  gvprintf(job, "]\n");
185 }
186 
187 static void write_radial_grad (GVJ_t * job, xdot_radial_grad* rg, state_t* sp)
188 {
189  indent(job, sp->Level);
190  gvprintf(job, "\"p0\": [%.03f,%.03f,%.03f],\n", rg->x0, rg->y0, rg->r0);
191  indent(job, sp->Level);
192  gvprintf(job, "\"p1\": [%.03f,%.03f,%.03f],\n", rg->x1, rg->y1, rg->r1);
193  indent(job, sp->Level);
194  write_stops (job, rg->n_stops, rg->stops, sp);
195 }
196 
197 static void write_linear_grad (GVJ_t * job, xdot_linear_grad* lg, state_t* sp)
198 {
199  indent(job, sp->Level);
200  gvprintf(job, "\"p0\": [%.03f,%.03f],\n", lg->x0, lg->y0);
201  indent(job, sp->Level);
202  gvprintf(job, "\"p1\": [%.03f,%.03f],\n", lg->x1, lg->y1);
203  indent(job, sp->Level);
204  write_stops (job, lg->n_stops, lg->stops, sp);
205 }
206 
207 static void write_xdot (xdot_op * op, GVJ_t * job, state_t* sp)
208 {
209  indent(job, sp->Level++);
210  gvputs(job, "{\n");
211  indent(job, sp->Level);
212 
213  switch (op->kind) {
214  case xd_filled_ellipse :
215  case xd_unfilled_ellipse :
216  gvprintf(job, "\"op\": \"%c\",\n",
217  (op->kind == xd_filled_ellipse ? 'E' : 'e'));
218  indent(job, sp->Level);
219  gvprintf(job, "\"rect\": [%.03f,%.03f,%.03f,%.03f]\n",
220  op->u.ellipse.x, op->u.ellipse.y, op->u.ellipse.w, op->u.ellipse.h);
221  break;
222  case xd_filled_polygon :
223  case xd_unfilled_polygon :
224  gvprintf(job, "\"op\": \"%c\",\n",
225  (op->kind == xd_filled_polygon ? 'P' : 'p'));
226  indent(job, sp->Level);
227  write_polyline (job, &op->u.polygon);
228  break;
229  case xd_filled_bezier :
230  case xd_unfilled_bezier :
231  gvprintf(job, "\"op\": \"%c\",\n",
232  (op->kind == xd_filled_bezier ? 'B' : 'b'));
233  indent(job, sp->Level);
234  write_polyline (job, &op->u.bezier);
235  break;
236  case xd_polyline :
237  gvprintf(job, "\"op\": \"L\",\n");
238  indent(job, sp->Level);
239  write_polyline (job, &op->u.polyline);
240  break;
241  case xd_text :
242  gvprintf(job, "\"op\": \"T\",\n");
243  indent(job, sp->Level);
244  gvprintf(job, "\"pt\": [%.03f,%.03f],\n", op->u.text.x, op->u.text.y);
245  indent(job, sp->Level);
246  gvprintf(job, "\"align\": \"%c\",\n",
247  (op->u.text.align == xd_left? 'l' :
248  (op->u.text.align == xd_center ? 'c' : 'r')));
249  indent(job, sp->Level);
250  gvprintf(job, "\"width\": %.03f,\n", op->u.text.width);
251  indent(job, sp->Level);
252  gvprintf(job, "\"text\": \"%s\"\n", stoj(op->u.text.text, sp));
253  break;
254  case xd_fill_color :
255  case xd_pen_color :
256  gvprintf(job, "\"op\": \"%c\",\n",
257  (op->kind == xd_fill_color ? 'C' : 'c'));
258  indent(job, sp->Level);
259  gvprintf(job, "\"grad\": \"none\",\n");
260  indent(job, sp->Level);
261  gvprintf(job, "\"color\": \"%s\"\n", stoj(op->u.color, sp));
262  break;
263  case xd_grad_pen_color :
264  case xd_grad_fill_color :
265  gvprintf(job, "\"op\": \"%c\",\n",
266  (op->kind == xd_grad_fill_color ? 'C' : 'c'));
267  indent(job, sp->Level);
268  if (op->u.grad_color.type == xd_none) {
269  gvprintf(job, "\"grad\": \"none\",\n");
270  indent(job, sp->Level);
271  gvprintf(job, "\"color\": \"%s\"\n",
272  stoj(op->u.grad_color.u.clr, sp));
273  }
274  else {
275  if (op->u.grad_color.type == xd_linear) {
276  gvprintf(job, "\"grad\": \"linear\",\n");
277  indent(job, sp->Level);
278  write_linear_grad (job, &op->u.grad_color.u.ling, sp);
279  }
280  else {
281  gvprintf(job, "\"grad\": \"radial\",\n");
282  indent(job, sp->Level);
283  write_radial_grad (job, &op->u.grad_color.u.ring, sp);
284  }
285  }
286  break;
287  case xd_font :
288  gvprintf(job, "\"op\": \"F\",\n");
289  indent(job, sp->Level);
290  gvprintf(job, "\"size\": %.03f,\n", op->u.font.size);
291  indent(job, sp->Level);
292  gvprintf(job, "\"face\": \"%s\"\n", stoj(op->u.font.name, sp));
293  break;
294  case xd_style :
295  gvprintf(job, "\"op\": \"S\",\n");
296  indent(job, sp->Level);
297  gvprintf(job, "\"style\": \"%s\"\n", stoj(op->u.style, sp));
298  break;
299  case xd_image :
300  break;
301  case xd_fontchar :
302  gvprintf(job, "\"op\": \"t\",\n");
303  indent(job, sp->Level);
304  gvprintf(job, "\"fontchar\": %d\n", op->u.fontchar);
305  break;
306  }
307  sp->Level--;
308  indent(job, sp->Level);
309  gvputs(job, "}");
310 }
311 
312 static void write_xdots (char * val, GVJ_t * job, state_t* sp)
313 {
314  xdot* cmds;
315  int i;
316  int not_first = 0;
317 
318  if (!val || (*val == '\0')) return;
319 
320  cmds = parseXDot(val);
321  if (!cmds) {
322  agerr(AGWARN, "Could not parse xdot \"%s\"\n", val);
323  return;
324  }
325 
326  gvputs(job, "\n");
327  indent(job, sp->Level++);
328  gvputs(job, "[\n");
329  for (i = 0; i < cmds->cnt; i++) {
330  if (not_first)
331  gvputs(job, ",\n");
332  else
333  not_first = 1;
334  write_xdot (cmds->ops+i, job, sp);
335  }
336  sp->Level--;
337  gvputs(job, "\n");
338  indent(job, sp->Level);
339  gvputs(job, "]");
340  freeXDot(cmds);
341 }
342 
343 static int isXDot (char* name)
344 {
345  return ((*name++ == '_') &&
346  (streq(name,"draw_") || streq(name,"ldraw_") ||
347  streq(name,"hdraw_") || streq(name,"tdraw_") ||
348  streq(name,"hldraw_") || streq(name,"tldraw_")));
349 }
350 
351 static void write_attrs(Agobj_t * obj, GVJ_t * job, state_t* sp)
352 {
353  Agraph_t* g = agroot(obj);
354  int type = AGTYPE(obj);
355  char* attrval;
356  Agsym_t* sym = agnxtattr(g, type, NULL);
357  if (!sym) return;
358 
359  for (; sym; sym = agnxtattr(g, type, sym)) {
360  if (!(attrval = agxget(obj, sym))) continue;
361  if ((*attrval == '\0') && !streq(sym->name, "label")) continue;
362  gvputs(job, ",\n");
363  indent(job, sp->Level);
364  gvprintf(job, "\"%s\": ", stoj(sym->name, sp));
365  if (sp->doXDot && isXDot(sym->name))
366  write_xdots(agxget(obj, sym), job, sp);
367  else
368  gvprintf(job, "\"%s\"", stoj(agxget(obj, sym), sp));
369  }
370 }
371 
372 static void write_hdr(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
373 {
374  char *name;
375 
376  name = agnameof(g);
377  indent(job, sp->Level);
378  gvprintf(job, "\"name\": \"%s\"", stoj (name, sp));
379 
380  if (top) {
381  gvputs(job, ",\n");
382  indent(job, sp->Level);
383  gvprintf(job, "\"directed\": %s,\n", (agisdirected(g)?"true":"false"));
384  indent(job, sp->Level);
385  gvprintf(job, "\"strict\": %s", (agisstrict(g)?"true":"false"));
386  }
387 }
388 
389 static void write_graph(Agraph_t * g, GVJ_t * job, int top, state_t* sp);
390 
391 static void write_subg(Agraph_t * g, GVJ_t * job, state_t* sp)
392 {
393  Agraph_t* sg;
394 
395  write_graph (g, job, FALSE, sp);
396  for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
397  gvputs(job, ",\n");
398  write_subg(sg, job, sp);
399  }
400 }
401 
402 /*
403 static int write_subgs(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
404 {
405  Agraph_t* sg;
406  int not_first = 0;
407 
408  sg = agfstsubg(g);
409  if (!sg) return 0;
410 
411  gvputs(job, ",\n");
412  indent(job, sp->Level++);
413  gvputs(job, "\"subgraphs\": [\n");
414  for (; sg; sg = agnxtsubg(sg)) {
415  if (not_first)
416  gvputs(job, ",\n");
417  else
418  not_first = 1;
419  write_subg (sg, job, top, sp);
420  }
421  sp->Level--;
422  gvputs(job, "\n");
423  indent(job, sp->Level);
424  gvputs(job, "]");
425  return 1;
426 }
427 */
428 
429 static int write_subgs(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
430 {
431  Agraph_t* sg;
432  int not_first = 0;
433 
434  sg = agfstsubg(g);
435  if (!sg) return 0;
436 
437  gvputs(job, ",\n");
438  indent(job, sp->Level++);
439  if (top)
440  gvputs(job, "\"objects\": [\n");
441  else {
442  gvputs(job, "\"subgraphs\": [\n");
443  indent(job, sp->Level);
444  }
445  for (; sg; sg = agnxtsubg(sg)) {
446  if (not_first)
447  gvputs(job, ",\n");
448  else
449  not_first = 1;
450  if (top)
451  write_subg (sg, job, sp);
452  else
453  gvprintf(job, "%d", GD_gid(sg));
454  }
455  if (!top) {
456  sp->Level--;
457  gvputs(job, "\n");
458  indent(job, sp->Level);
459  gvputs(job, "]");
460  }
461 
462  return 1;
463 }
464 
465 static void write_edge(Agedge_t * e, GVJ_t * job, int top, state_t* sp)
466 {
467  if (top) {
468  indent(job, sp->Level++);
469  gvputs(job, "{\n");
470  indent(job, sp->Level);
471  gvprintf(job, "\"_gvid\": %d,\n", ED_gid(e));
472  indent(job, sp->Level);
473  gvprintf(job, "\"tail\": %d,\n", ND_gid(agtail(e)));
474  indent(job, sp->Level);
475  gvprintf(job, "\"head\": %d", ND_gid(aghead(e)));
476  write_attrs((Agobj_t*)e, job, sp);
477  gvputs(job, "\n");
478  sp->Level--;
479  indent(job, sp->Level);
480  gvputs(job, "}");
481  }
482  else {
483  gvprintf(job, "%d", ED_gid(e));
484  }
485 }
486 
487 static int write_edges(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
488 {
489  Agnode_t* np;
490  Agedge_t* ep;
491  int not_first = 0;
492 
493  np = agfstnode(g);
494  if (!np) return 0;
495  ep = NULL;
496  /* find a first edge */
497  for (; np; np = agnxtnode(g,np)) {
498  for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) {
499  if (ep) break;
500  }
501  if (ep) break;
502  }
503  if (!ep) return 0;
504 
505  gvputs(job, ",\n");
506  indent(job, sp->Level++);
507  gvputs(job, "\"edges\": [\n");
508  if (!top)
509  indent(job, sp->Level);
510  for (; np; np = agnxtnode(g,np)) {
511  for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) {
512  if (not_first)
513  if (top)
514  gvputs(job, ",\n");
515  else
516  gvputs(job, ",");
517  else
518  not_first = 1;
519  write_edge(ep, job, top, sp);
520  }
521  }
522  sp->Level--;
523  gvputs(job, "\n");
524  indent(job, sp->Level);
525  gvputs(job, "]");
526  return 1;
527 }
528 
529 static void write_node(Agnode_t * n, GVJ_t * job, int top, state_t* sp)
530 {
531  if (top) {
532  indent(job, sp->Level++);
533  gvputs(job, "{\n");
534  indent(job, sp->Level);
535  gvprintf(job, "\"_gvid\": %d,\n", ND_gid(n));
536  indent(job, sp->Level);
537  gvprintf(job, "\"name\": \"%s\"", stoj (agnameof(n), sp));
538  write_attrs((Agobj_t*)n, job, sp);
539  gvputs(job, "\n");
540  sp->Level--;
541  indent(job, sp->Level);
542  gvputs(job, "}");
543  }
544  else {
545  gvprintf(job, "%d", ND_gid(n));
546  }
547 }
548 
549 static int write_nodes(Agraph_t * g, GVJ_t * job, int top, int has_subgs, state_t* sp)
550 {
551  Agnode_t* n;
552  int not_first = 0;
553 
554  n = agfstnode(g);
555  if (!n) {
556  if (has_subgs && top) {
557  sp->Level--;
558  gvputs(job, "\n");
559  indent(job, sp->Level);
560  gvputs(job, "]");
561  }
562  return 0;
563  }
564  gvputs(job, ",\n");
565  if (top) {
566  if (!has_subgs) {
567  indent(job, sp->Level++);
568  gvputs(job, "\"objects\": [\n");
569  }
570  }
571  else {
572  indent(job, sp->Level++);
573  gvputs(job, "\"nodes\": [\n");
574  indent(job, sp->Level);
575  }
576  for (; n; n = agnxtnode(g, n)) {
577  if (IS_CLUST_NODE(n)) continue;
578  if (not_first)
579  if (top)
580  gvputs(job, ",\n");
581  else
582  gvputs(job, ",");
583  else
584  not_first = 1;
585  write_node (n, job, top, sp);
586  }
587  sp->Level--;
588  gvputs(job, "\n");
589  indent(job, sp->Level);
590  gvputs(job, "]");
591  return 1;
592 }
593 
594 typedef struct {
596  char* id;
597  int v;
598 } intm;
599 
600 static void freef(Dt_t * dt, intm * obj, Dtdisc_t * disc)
601 {
602  free(obj->id);
603  free(obj);
604 }
605 
606 static Dtdisc_t intDisc = {
607  offsetof(intm, id),
608  -1,
609  offsetof(intm, link),
610  (Dtmake_f) NULL,
611  (Dtfree_f) freef,
612  (Dtcompar_f) NULL,
613  0,
614  0,
615  0
616 };
617 
618 #define NEW(t) (t*)calloc(1,sizeof(t))
619 
620 static int lookup (Dt_t* map, char* name)
621 {
622  intm* ip = (intm*)dtmatch(map, name);
623  if (ip) return ip->v;
624  else return -1;
625 }
626 
627 static void insert (Dt_t* map, char* name, int v)
628 {
629  intm* ip = (intm*)dtmatch(map, name);
630 
631  if (ip) {
632  if (ip->v != v)
633  agerr(AGWARN, "Duplicate cluster name \"%s\"\n", name);
634  return;
635  }
636  ip = NEW(intm);
637  ip->id = strdup(name);
638  ip->v = v;
639  dtinsert (map, ip);
640 }
641 
642 static int label_subgs(Agraph_t* g, int lbl, Dt_t* map)
643 {
644  Agraph_t* sg;
645 
646  if (g != agroot(g)) {
647  GD_gid(g) = lbl++;
648  if (IS_CLUSTER(g))
649  insert (map, agnameof(g), GD_gid(g));
650  }
651  for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
652  lbl = label_subgs(sg, lbl, map);
653  }
654  return lbl;
655 }
656 
657 
658 static void write_graph(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
659 {
660  Agnode_t* np;
661  Agedge_t* ep;
662  int ncnt = 0;
663  int ecnt = 0;
664  int sgcnt = 0;
665  int has_subgs;
666  Dt_t* map;
667 
668  if (top) {
669  map = dtopen (&intDisc, Dtoset);
670  aginit(g, AGNODE, ID, sizeof(gvid_t), FALSE);
671  aginit(g, AGEDGE, ID, sizeof(gvid_t), FALSE);
672  aginit(g, AGRAPH, ID, -((int)sizeof(gvid_t)), FALSE);
673  sgcnt = label_subgs(g, sgcnt, map);
674  for (np = agfstnode(g); np; np = agnxtnode(g,np)) {
675  if (IS_CLUST_NODE(np)) {
676  ND_gid(np) = lookup(map, agnameof(np));
677  }
678  else {
679  ND_gid(np) = sgcnt + ncnt++;
680  }
681  for (ep = agfstout(g, np); ep; ep = agnxtout(g,ep)) {
682  ED_gid(ep) = ecnt++;
683  }
684  }
685  dtclose(map);
686  }
687 
688  indent(job, sp->Level++);
689  gvputs(job, "{\n");
690  write_hdr(g, job, top, sp);
691  write_attrs((Agobj_t*)g, job, sp);
692  if (top) {
693  gvputs(job, ",\n");
694  indent(job, sp->Level);
695  gvprintf(job, "\"_subgraph_cnt\": %d", sgcnt);
696  } else {
697  gvputs(job, ",\n");
698  indent(job, sp->Level);
699  gvprintf(job, "\"_gvid\": %d", GD_gid(g));
700  }
701  has_subgs = write_subgs(g, job, top, sp);
702  write_nodes (g, job, top, has_subgs, sp);
703  write_edges (g, job, top, sp);
704  gvputs(job, "\n");
705  sp->Level--;
706  indent(job, sp->Level);
707  if (top)
708  gvputs(job, "}\n");
709  else
710  gvputs(job, "}");
711 }
712 
713 typedef int (*putstrfn) (void *chan, const char *str);
714 typedef int (*flushfn) (void *chan);
715 
716 static void json_end_graph(GVJ_t *job)
717 {
718  graph_t *g = job->obj->u.g;
719  state_t sp;
720  Agiodisc_t* io_save;
721  static Agiodisc_t io;
722 
723  if (io.afread == NULL) {
724  io.afread = AgIoDisc.afread;
725  io.putstr = (putstrfn)gvputs;
726  io.flush = (flushfn)gvflush;
727  }
728 
729  io_save = g->clos->disc.io;
730  g->clos->disc.io = &io;
731 
732  set_attrwf(g, TRUE, FALSE);
733  sp.Level = 0;
734  sp.isLatin = (GD_charset(g) == CHAR_LATIN1);
735  sp.doXDot = ((job->render.id == FORMAT_JSON) || (job->render.id == FORMAT_XDOT_JSON));
736  sp.Attrs_not_written_flag = 0;
737  write_graph(g, job, TRUE, &sp);
738  /* agwrite(g, (FILE*)job); */
739 }
740 
742  0, /* json_begin_job */
743  0, /* json_end_job */
744  json_begin_graph,
745  json_end_graph,
746  0, /* json_begin_layer */
747  0, /* json_end_layer */
748  0, /* json_begin_page */
749  0, /* json_end_page */
750  0, /* json_begin_cluster */
751  0, /* json_end_cluster */
752  0, /* json_begin_nodes */
753  0, /* json_end_nodes */
754  0, /* json_begin_edges */
755  0, /* json_end_edges */
756  0, /* json_begin_node */
757  0, /* json_end_node */
758  0, /* json_begin_edge */
759  0, /* json_end_edge */
760  0, /* json_begin_anchor */
761  0, /* json_end_anchor */
762  0, /* json_begin_label */
763  0, /* json_end_label */
764  0, /* json_textspan */
765  0, /* json_resolve_color */
766  0, /* json_ellipse */
767  0, /* json_polygon */
768  0, /* json_bezier */
769  0, /* json_polyline */
770  0, /* json_comment */
771  0, /* json_library_shape */
772 };
773 
775  GVRENDER_DOES_TRANSFORM, /* not really - uses raw graph coords */ /* flags */
776  0., /* default pad - graph units */
777  NULL, /* knowncolors */
778  0, /* sizeof knowncolors */
779  COLOR_STRING, /* color_type */
780 };
781 
783  GVRENDER_DOES_TRANSFORM /* not really - uses raw graph coords */
786  | GVRENDER_DOES_TOOLTIPS, /* flags */
787  0., /* default pad - graph units */
788  NULL, /* knowncolors */
789  0, /* sizeof knowncolors */
790  COLOR_STRING, /* color_type */
791 };
792 
794  LAYOUT_NOT_REQUIRED, /* flags */
795  {0.,0.}, /* default margin - points */
796  {0.,0.}, /* default page width, height - points */
797  {72.,72.}, /* default dpi */
798 };
799 
801  0, /* flags */
802  {0.,0.}, /* default margin - points */
803  {0.,0.}, /* default page width, height - points */
804  {72.,72.}, /* default dpi */
805 };
806 
808  {FORMAT_JSON, "json", 1, &json_engine, &render_features_json},
809  {FORMAT_JSON0, "json0", 1, &json_engine, &render_features_json},
810  {FORMAT_DOT_JSON, "dot_json", 1, &json_engine, &render_features_json},
811  {FORMAT_XDOT_JSON, "xdot_json", 1, &json_engine, &render_features_json},
812  {0, NULL, 0, NULL, NULL}
813 };
814 
816  {FORMAT_JSON, "json:json", 1, NULL, &device_features_json},
817  {FORMAT_JSON0, "json0:json", 1, NULL, &device_features_json},
818  {FORMAT_DOT_JSON, "dot_json:json", 1, NULL, &device_features_json_nop},
819  {FORMAT_XDOT_JSON, "xdot_json:json", 1, NULL, &device_features_json_nop},
820  {0, NULL, 0, NULL, NULL}
821 };
int(* Dtcompar_f)(Dt_t *, void *, void *, Dtdisc_t *)
Definition: cdt.h:40
xdot_linear_grad ling
Definition: xdot.h:65
double r0
Definition: xdot.h:55
unsigned char * buf
Definition: agxbuf.h:35
xdot_color grad_color
Definition: xdot.h:138
Definition: xdot.h:38
CDT_API int dtclose(Dt_t *)
double y0
Definition: xdot.h:48
union _xdot_op::@54 u
void *(* Dtmake_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:38
char * latin1ToUTF8(char *s)
Definition: utils.c:1561
boolean isLatin
#define LAYOUT_NOT_REQUIRED
Definition: gvcjob.h:110
#define AGATTRWF(obj)
Definition: cgraph.h:116
#define agxbuse(X)
Definition: agxbuf.h:83
CGRAPH_API Agiodisc_t AgIoDisc
Definition: cgraph.h:199
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
Definition: attr.c:340
double size
Definition: xdot.h:100
char * text
Definition: xdot.h:91
Definition: xdot.h:109
xdot_color_stop * stops
Definition: xdot.h:58
int n_stops
Definition: xdot.h:50
xdot_polyline bezier
Definition: xdot.h:134
CDT_API Dtmethod_t * Dtoset
Definition: cdt.h:166
char * name
Definition: cgraph.h:326
#define ND_gid(n)
xdot_color_stop * stops
Definition: xdot.h:51
char * name
Definition: xdot.h:101
CGRAPH_API int agisdirected(Agraph_t *g)
Definition: graph.c:182
size_t agxbput(agxbuf *xb, const char *s)
Definition: agxbuf.c:84
void gvFreeCloneGVC(GVC_t *)
Definition: gvcontext.c:125
Definition: xdot.h:108
Definition: cdt.h:80
Definition: xdot.h:71
Definition: xdot.h:71
Definition: xdot.h:128
double x0
Definition: xdot.h:55
double x
Definition: xdot.h:79
xdot_grad_type type
Definition: xdot.h:62
gvrender_engine_t json_engine
xdot_rect ellipse
Definition: xdot.h:131
graph_t * g
Definition: gvcint.h:106
char * clr
Definition: xdot.h:64
double x1
Definition: xdot.h:49
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
xdot * parseXDot(char *s)
Definition: xdot.c:496
double y1
Definition: xdot.h:49
xdot_kind kind
Definition: xdot.h:129
CGRAPH_API Agraph_t * agfstsubg(Agraph_t *g)
Definition: subg.c:72
Definition: gvcjob.h:271
CGRAPH_API Agraph_t * agroot(void *obj)
Definition: obj.c:169
CGRAPH_API Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition: edge.c:25
GVC_t * gvCloneGVC(GVC_t *)
Definition: gvcontext.c:113
#define IS_CLUSTER(s)
double w
Definition: xdot.h:79
gvplugin_installed_t gvdevice_json_types[]
#define GVRENDER_DOES_TRANSFORM
Definition: gvcjob.h:97
int(* flushfn)(void *chan)
#define AGTYPE(obj)
Definition: cgraph.h:113
Definition: cgraph.h:388
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition: dtopen.c:9
obj_state_t * obj
Definition: gvcjob.h:278
#define agxbputc(X, C)
Definition: agxbuf.h:77
CGRAPH_API Agraph_t * agnxtsubg(Agraph_t *subg)
Definition: subg.c:77
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
Definition: edge.c:525
int gvputs(GVJ_t *job, const char *s)
Definition: gvdevice.c:270
double h
Definition: xdot.h:79
Agdisc_t disc
Definition: cgraph.h:229
gvplugin_installed_t gvrender_json_types[]
Definition: xdot.h:148
char * style
Definition: xdot.h:140
#define GVRENDER_DOES_TARGETS
Definition: gvcjob.h:107
CGRAPH_API Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition: node.c:45
int
Definition: grammar.c:1264
#define GVRENDER_DOES_TOOLTIPS
Definition: gvcjob.h:106
CGRAPH_API int agisstrict(Agraph_t *g)
Definition: graph.c:192
Definition: xdot.h:109
gvplugin_active_render_t render
Definition: gvcjob.h:294
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
Definition: edge.c:533
gvrender_features_t render_features_json1
char * color
Definition: xdot.h:137
int(* flush)(void *chan)
Definition: cgraph.h:185
Definition: gvcint.h:70
CGRAPH_API char * agnameof(void *)
Definition: id.c:143
int(* afread)(void *chan, char *buf, int bufsize)
Definition: cgraph.h:183
#define dtmatch(d, o)
Definition: cdt.h:261
gvdevice_features_t device_features_json
htmllabel_t * lbl
Definition: htmlparse.c:81
unsigned int fontchar
Definition: xdot.h:141
int n_stops
Definition: xdot.h:57
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
Definition: agxbuf.c:25
GVC_t * gvc
Definition: gvcjob.h:272
CGRAPH_API Agnode_t * agfstnode(Agraph_t *g)
Definition: node.c:38
CGRAPH_API void aginit(Agraph_t *g, int kind, char *rec_name, int rec_size, int move_to_front)
Definition: rec.c:198
double y
Definition: xdot.h:79
Definition: grammar.c:79
int(* putstrfn)(void *chan, const char *str)
Definition: cgraph.h:83
#define AGNODE
Definition: cgraph.h:101
double y0
Definition: xdot.h:55
double width
Definition: xdot.h:90
boolean doXDot
graph_t * g
Definition: gvcjob.h:195
#define dtinsert(d, o)
Definition: cdt.h:262
format_type
int cnt
Definition: xdot.h:83
xdot_radial_grad ring
Definition: xdot.h:66
#define GVRENDER_DOES_MAPS
Definition: gvcjob.h:100
#define NULL
Definition: logic.h:39
#define GD_charset(g)
Definition: types.h:371
int cnt
Definition: xdot.h:149
xdot_op * ops
Definition: xdot.h:151
#define streq(s, t)
Definition: cghdr.h:52
#define CHAR_LATIN1
Definition: const.h:205
GVC_t * gvc
Definition: htmlparse.c:87
#define top(sp)
Definition: stack.h:35
double x1
Definition: xdot.h:56
double x
Definition: xdot.h:88
Agiodisc_t * io
Definition: cgraph.h:192
union obj_state_s::@23 u
int gvflush(GVJ_t *job)
Definition: gvdevice.c:290
int gvRender(GVC_t *gvc, graph_t *g, const char *format, FILE *out)
Definition: gvc.c:85
gvrender_features_t render_features_json
#define IS_CLUST_NODE(n)
Definition: macros.h:31
#define ID
xdot_point * pts
Definition: xdot.h:84
void(* Dtfree_f)(Dt_t *, void *, Dtdisc_t *)
Definition: cdt.h:39
Definition: cdt.h:99
void freeXDot(xdot *x)
Definition: xdot.c:945
xdot_polyline polygon
Definition: xdot.h:132
xdot_text text
Definition: xdot.h:135
agxbuf * str
Definition: htmlparse.c:85
int(* putstr)(void *chan, const char *str)
Definition: cgraph.h:184
Definition: agxbuf.h:34
double y
Definition: xdot.h:88
char * agxget(void *obj, Agsym_t *sym)
Definition: attr.c:444
boolean Attrs_not_written_flag
xdot_align align
Definition: xdot.h:89
double y1
Definition: xdot.h:56
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition: edge.c:40
Definition: xdot.h:37
Agclos_t * clos
Definition: cgraph.h:248
#define ED_gid(n)
union xdot_color::@53 u
#define AGEDGE
Definition: cgraph.h:104
void attach_attrs(graph_t *g)
Definition: output.c:399
double x0
Definition: xdot.h:48
gvdevice_features_t device_features_json_nop
Dtlink_t link
#define FALSE
Definition: cgraph.h:35
xdot_polyline polyline
Definition: xdot.h:133
double r1
Definition: xdot.h:56
void gvprintf(GVJ_t *job, const char *format,...)
Definition: gvdevice.c:389
Definition: xdot.h:109
#define NEW(t)
#define AGRAPH
Definition: cgraph.h:100
xdot_font font
Definition: xdot.h:139
#define GD_gid(n)
#define TRUE
Definition: cgraph.h:38