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