Graphviz 14.1.3~dev.20260129.0812
Loading...
Searching...
No Matches
xdot.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 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 v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <stdlib.h>
14#include <string.h>
15#include <util/agxbuf.h>
16#include <util/alloc.h>
17#include <util/gv_ctype.h>
18#include <util/prisize_t.h>
19#include <util/unreachable.h>
20#include <xdot/xdot.h>
21
22/* the parse functions should return NULL on error */
23static char *parseReal(char *s, double *fp) {
24 char *p;
25 double d;
26
27 d = strtod(s, &p);
28 if (p == s)
29 return 0;
30
31 *fp = d;
32 return (p);
33}
34
35static char *parseInt(char *s, int *ip) {
36 char *endp;
37
38 *ip = (int)strtol(s, &endp, 10);
39 if (s == endp)
40 return 0;
41 else
42 return endp;
43}
44
45static char *parseUInt(char *s, unsigned int *ip) {
46 char *endp;
47
48 *ip = (unsigned int)strtoul(s, &endp, 10);
49 if (s == endp)
50 return 0;
51 else
52 return endp;
53}
54
55static char *parseRect(char *s, xdot_rect *rp) {
56 char *endp;
57
58 rp->x = strtod(s, &endp);
59 if (s == endp)
60 return 0;
61 else
62 s = endp;
63
64 rp->y = strtod(s, &endp);
65 if (s == endp)
66 return 0;
67 else
68 s = endp;
69
70 rp->w = strtod(s, &endp);
71 if (s == endp)
72 return 0;
73 else
74 s = endp;
75
76 rp->h = strtod(s, &endp);
77 if (s == endp)
78 return 0;
79 else
80 s = endp;
81
82 return s;
83}
84
85static char *parsePolyline(char *s, xdot_polyline *pp) {
86 unsigned i;
87 xdot_point *pts;
88 xdot_point *ps;
89 char *endp;
90
91 s = parseUInt(s, &i);
92 if (!s)
93 return NULL;
94 pts = ps = gv_calloc(i, sizeof(ps[0]));
95 pp->cnt = i;
96 for (i = 0; i < pp->cnt; i++) {
97 ps->x = strtod(s, &endp);
98 if (s == endp) {
99 free(pts);
100 return NULL;
101 } else {
102 s = endp;
103 }
104 ps->y = strtod(s, &endp);
105 if (s == endp) {
106 free(pts);
107 return NULL;
108 } else {
109 s = endp;
110 }
111 ps->z = 0;
112 ps++;
113 }
114 pp->pts = pts;
115 return s;
116}
117
118static char *parseString(char *s, char **sp) {
119 int i;
120 s = parseInt(s, &i);
121 if (!s || i <= 0)
122 return 0;
123 while (*s && *s != '-')
124 s++;
125 if (*s) {
126 s++;
127 } else {
128 return 0;
129 }
130
131 // The leading number we just read indicates the count of originating
132 // characters in the upcoming string. But the string may contain \-escaped
133 // characters. So the count alone does not tell us how many bytes we need to
134 // now read.
135 agxbuf c = {0};
136 int j = 0;
137 for (int accounted = 0; accounted < i; ++j) {
138 if (s[j] == '\0') {
139 agxbfree(&c);
140 return 0;
141 }
142 agxbputc(&c, s[j]);
143 // only count this character if it was not an escape prefix
144 if (s[j] != '\\' || (j > 0 && s[j - 1] == '\\')) {
145 ++accounted;
146 }
147 }
148
149 *sp = agxbdisown(&c);
150 return s + j;
151}
152
153static char *parseAlign(char *s, xdot_align *ap) {
154 int i;
155 s = parseInt(s, &i);
156
157 if (i < 0)
158 *ap = xd_left;
159 else if (i > 0)
160 *ap = xd_right;
161 else
162 *ap = xd_center;
163 return s;
164}
165
166#define CHK(s) \
167 if (!s) { \
168 *error = 1; \
169 return 0; \
170 }
171
172static char *parseOp(xdot_op *op, char *s, drawfunc_t ops[], int *error) {
173 char *cs;
174 xdot_color clr;
175
176 *error = 0;
177 while (gv_isspace(*s))
178 s++;
179 switch (*s++) {
180 case 'E':
182 s = parseRect(s, &op->u.ellipse);
183 CHK(s);
184 if (ops)
185 op->drawfunc = ops[xop_ellipse];
186 break;
187
188 case 'e':
190 s = parseRect(s, &op->u.ellipse);
191 CHK(s);
192 if (ops)
193 op->drawfunc = ops[xop_ellipse];
194 break;
195
196 case 'P':
198 s = parsePolyline(s, &op->u.polygon);
199 CHK(s);
200 if (ops)
201 op->drawfunc = ops[xop_polygon];
202 break;
203
204 case 'p':
206 s = parsePolyline(s, &op->u.polygon);
207 CHK(s);
208 if (ops)
209 op->drawfunc = ops[xop_polygon];
210 break;
211
212 case 'b':
214 s = parsePolyline(s, &op->u.bezier);
215 CHK(s);
216 if (ops)
217 op->drawfunc = ops[xop_bezier];
218 break;
219
220 case 'B':
222 s = parsePolyline(s, &op->u.bezier);
223 CHK(s);
224 if (ops)
225 op->drawfunc = ops[xop_bezier];
226 break;
227
228 case 'c':
229 s = parseString(s, &cs);
230 CHK(s);
231 cs = parseXDotColor(cs, &clr);
232 CHK(cs);
233 if (clr.type == xd_none) {
234 op->kind = xd_pen_color;
235 op->u.color = clr.u.clr;
236 if (ops)
238 } else {
240 op->u.grad_color = clr;
241 if (ops)
243 }
244 break;
245
246 case 'C':
247 s = parseString(s, &cs);
248 CHK(s);
249 cs = parseXDotColor(cs, &clr);
250 CHK(cs);
251 if (clr.type == xd_none) {
252 op->kind = xd_fill_color;
253 op->u.color = clr.u.clr;
254 if (ops)
256 } else {
258 op->u.grad_color = clr;
259 if (ops)
261 }
262 break;
263
264 case 'L':
265 op->kind = xd_polyline;
266 s = parsePolyline(s, &op->u.polyline);
267 CHK(s);
268 if (ops)
270 break;
271
272 case 'T':
273 op->kind = xd_text;
274 s = parseReal(s, &op->u.text.x);
275 CHK(s);
276 s = parseReal(s, &op->u.text.y);
277 CHK(s);
278 s = parseAlign(s, &op->u.text.align);
279 CHK(s);
280 s = parseReal(s, &op->u.text.width);
281 CHK(s);
282 s = parseString(s, &op->u.text.text);
283 CHK(s);
284 if (ops)
285 op->drawfunc = ops[xop_text];
286 break;
287
288 case 'F':
289 op->kind = xd_font;
290 s = parseReal(s, &op->u.font.size);
291 CHK(s);
292 s = parseString(s, &op->u.font.name);
293 CHK(s);
294 if (ops)
295 op->drawfunc = ops[xop_font];
296 break;
297
298 case 'S':
299 op->kind = xd_style;
300 s = parseString(s, &op->u.style);
301 CHK(s);
302 if (ops)
303 op->drawfunc = ops[xop_style];
304 break;
305
306 case 'I':
307 op->kind = xd_image;
308 s = parseRect(s, &op->u.image.pos);
309 CHK(s);
310 s = parseString(s, &op->u.image.name);
311 CHK(s);
312 if (ops)
313 op->drawfunc = ops[xop_image];
314 break;
315
316 case 't':
317 op->kind = xd_fontchar;
318 s = parseUInt(s, &op->u.fontchar);
319 CHK(s);
320 if (ops)
322 break;
323
324 case '\0':
325 s = 0;
326 break;
327
328 default:
329 *error = 1;
330 s = 0;
331 break;
332 }
333 return s;
334}
335
336#define XDBSIZE 100
337
338/* parseXDotFOn:
339 * Parse and append additional xops onto a given xdot object.
340 * Return x.
341 */
342xdot *parseXDotFOn(char *s, drawfunc_t fns[], size_t sz, xdot *x) {
343 xdot_op op;
344 char *ops;
345 size_t oldsz, bufsz;
346 int error;
347
348 if (!s)
349 return x;
350
351 if (!x) {
352 x = gv_alloc(sizeof(*x));
353 if (sz <= sizeof(xdot_op))
354 sz = sizeof(xdot_op);
355
356 /* cnt, freefunc, ops, flags zeroed by gv_alloc */
357 x->sz = sz;
358 }
359 size_t initcnt = x->cnt;
360 sz = x->sz;
361
362 if (initcnt == 0) {
363 bufsz = XDBSIZE;
364 ops = gv_calloc(XDBSIZE, sz);
365 } else {
366 bufsz = initcnt + XDBSIZE;
367 ops = gv_recalloc(x->ops, initcnt, bufsz, sz);
368 }
369
370 while ((s = parseOp(&op, s, fns, &error))) {
371 if (x->cnt == bufsz) {
372 oldsz = bufsz;
373 bufsz *= 2;
374 ops = gv_recalloc(ops, oldsz, bufsz, sz);
375 }
376 *(xdot_op *)(ops + x->cnt * sz) = op;
377 x->cnt++;
378 }
379 if (error)
381 if (x->cnt) {
382 x->ops = gv_recalloc(ops, bufsz, x->cnt, sz);
383 } else {
384 free(ops);
385 free(x);
386 x = NULL;
387 }
388
389 return x;
390}
391
392xdot *parseXDotF(char *s, drawfunc_t fns[], size_t sz) {
393 return parseXDotFOn(s, fns, sz, NULL);
394}
395
396xdot *parseXDot(char *s) { return parseXDotF(s, 0, 0); }
397
398typedef int (*pf)(void *, char *, ...);
399
400static void printRect(xdot_rect *r, pf print, void *info) {
401 agxbuf buf = {0};
402
403 agxbprint(&buf, " %.02f", r->x);
404 agxbuf_trim_zeros(&buf);
405 print(info, "%s", agxbuse(&buf));
406 agxbprint(&buf, " %.02f", r->y);
407 agxbuf_trim_zeros(&buf);
408 print(info, "%s", agxbuse(&buf));
409 agxbprint(&buf, " %.02f", r->w);
410 agxbuf_trim_zeros(&buf);
411 print(info, "%s", agxbuse(&buf));
412 agxbprint(&buf, " %.02f", r->h);
413 agxbuf_trim_zeros(&buf);
414 print(info, "%s", agxbuse(&buf));
415 agxbfree(&buf);
416}
417
418static void printPolyline(xdot_polyline *p, pf print, void *info) {
419 agxbuf buf = {0};
420
421 print(info, " %" PRISIZE_T, p->cnt);
422 for (size_t i = 0; i < p->cnt; i++) {
423 agxbprint(&buf, " %.02f", p->pts[i].x);
424 agxbuf_trim_zeros(&buf);
425 print(info, "%s", agxbuse(&buf));
426 agxbprint(&buf, " %.02f", p->pts[i].y);
427 agxbuf_trim_zeros(&buf);
428 print(info, "%s", agxbuse(&buf));
429 }
430 agxbfree(&buf);
431}
432
433static void printString(char *p, pf print, void *info) {
434 print(info, " %" PRISIZE_T " -%s", strlen(p), p);
435}
436
437static void printFloat(double f, pf print, void *info, int space) {
438 agxbuf buf = {0};
439
440 if (space)
441 agxbprint(&buf, " %.02f", f);
442 else
443 agxbprint(&buf, "%.02f", f);
444 agxbuf_trim_zeros(&buf);
445 print(info, "%s", agxbuse(&buf));
446 agxbfree(&buf);
447}
448
449static void printAlign(xdot_align a, pf print, void *info) {
450 switch (a) {
451 case xd_left:
452 print(info, " -1");
453 break;
454 case xd_right:
455 print(info, " 1");
456 break;
457 case xd_center:
458 print(info, " 0");
459 break;
460 default:
461 UNREACHABLE();
462 }
463}
464
465static void toGradString(agxbuf *xb, xdot_color *cp) {
466 int i, n_stops;
467 xdot_color_stop *stops;
468
469 if (cp->type == xd_linear) {
470 agxbputc(xb, '[');
471 printFloat(cp->u.ling.x0, (pf)agxbprint, xb, 0);
472 printFloat(cp->u.ling.y0, (pf)agxbprint, xb, 1);
473 printFloat(cp->u.ling.x1, (pf)agxbprint, xb, 1);
474 printFloat(cp->u.ling.y1, (pf)agxbprint, xb, 1);
475 n_stops = cp->u.ling.n_stops;
476 stops = cp->u.ling.stops;
477 } else {
478 agxbputc(xb, '(');
479 printFloat(cp->u.ring.x0, (pf)agxbprint, xb, 0);
480 printFloat(cp->u.ring.y0, (pf)agxbprint, xb, 1);
481 printFloat(cp->u.ring.r0, (pf)agxbprint, xb, 1);
482 printFloat(cp->u.ring.x1, (pf)agxbprint, xb, 1);
483 printFloat(cp->u.ring.y1, (pf)agxbprint, xb, 1);
484 printFloat(cp->u.ring.r1, (pf)agxbprint, xb, 1);
485 n_stops = cp->u.ring.n_stops;
486 stops = cp->u.ring.stops;
487 }
488 agxbprint(xb, " %d", n_stops);
489 for (i = 0; i < n_stops; i++) {
490 printFloat(stops[i].frac, (pf)agxbprint, xb, 1);
491 printString(stops[i].color, (pf)agxbprint, xb);
492 }
493
494 if (cp->type == xd_linear)
495 agxbputc(xb, ']');
496 else
497 agxbputc(xb, ')');
498}
499
500typedef void (*print_op)(xdot_op *op, pf print, void *info, int more);
501
502static void printXDot_Op(xdot_op *op, pf print, void *info, int more) {
503 agxbuf xb = {0};
504 switch (op->kind) {
506 print(info, "E");
507 printRect(&op->u.ellipse, print, info);
508 break;
510 print(info, "e");
511 printRect(&op->u.ellipse, print, info);
512 break;
514 print(info, "P");
516 break;
518 print(info, "p");
520 break;
521 case xd_filled_bezier:
522 print(info, "b");
524 break;
526 print(info, "B");
528 break;
529 case xd_pen_color:
530 print(info, "c");
532 break;
534 print(info, "c");
535 toGradString(&xb, &op->u.grad_color);
537 break;
538 case xd_fill_color:
539 print(info, "C");
541 break;
543 print(info, "C");
544 toGradString(&xb, &op->u.grad_color);
546 break;
547 case xd_polyline:
548 print(info, "L");
550 break;
551 case xd_text:
552 print(info, "T %.f %.f", op->u.text.x, op->u.text.y);
554 print(info, " %.f", op->u.text.width);
556 break;
557 case xd_font:
558 print(info, "F");
559 printFloat(op->u.font.size, print, info, 1);
561 break;
562 case xd_fontchar:
563 print(info, "t %u", op->u.fontchar);
564 break;
565 case xd_style:
566 print(info, "S");
568 break;
569 case xd_image:
570 print(info, "I");
571 printRect(&op->u.image.pos, print, info);
573 break;
574 default: // invalid type; ignore
575 break;
576 }
577 if (more)
578 print(info, " ");
579 agxbfree(&xb);
580}
581
582static void jsonRect(xdot_rect *r, pf print, void *info) {
583 print(info, "[%.06f,%.06f,%.06f,%.06f]", r->x, r->y, r->w, r->h);
584}
585
586static void jsonPolyline(xdot_polyline *p, pf print, void *info) {
587 print(info, "[");
588 for (size_t i = 0; i < p->cnt; i++) {
589 print(info, "%.06f,%.06f", p->pts[i].x, p->pts[i].y);
590 if (i < p->cnt - 1)
591 print(info, ",");
592 }
593 print(info, "]");
594}
595
596static void jsonString(char *p, pf print, void *info) {
597 char c;
598
599 print(info, "\"");
600 while ((c = *p++)) {
601 if (c == '"')
602 print(info, "\\\"");
603 else if (c == '\\')
604 print(info, "\\\\");
605 else
606 print(info, "%c", c);
607 }
608 print(info, "\"");
609}
610
611static void jsonXDot_Op(xdot_op *op, pf print, void *info, int more) {
612 agxbuf xb = {0};
613 switch (op->kind) {
615 print(info, "{\"E\" : ");
616 jsonRect(&op->u.ellipse, print, info);
617 break;
619 print(info, "{\"e\" : ");
620 jsonRect(&op->u.ellipse, print, info);
621 break;
623 print(info, "{\"P\" : ");
625 break;
627 print(info, "{\"p\" : ");
629 break;
630 case xd_filled_bezier:
631 print(info, "{\"b\" : ");
633 break;
635 print(info, "{\"B\" : ");
637 break;
638 case xd_pen_color:
639 print(info, "{\"c\" : ");
640 jsonString(op->u.color, print, info);
641 break;
643 print(info, "{\"c\" : ");
644 toGradString(&xb, &op->u.grad_color);
646 break;
647 case xd_fill_color:
648 print(info, "{\"C\" : ");
649 jsonString(op->u.color, print, info);
650 break;
652 print(info, "{\"C\" : ");
653 toGradString(&xb, &op->u.grad_color);
655 break;
656 case xd_polyline:
657 print(info, "{\"L\" :");
659 break;
660 case xd_text:
661 print(info, "{\"T\" : [ %.f, %.f,", op->u.text.x, op->u.text.y);
663 print(info, ", %.f,", op->u.text.width);
665 print(info, "]");
666 break;
667 case xd_font:
668 print(info, "{\"F\" : [");
669 op->kind = xd_font;
670 printFloat(op->u.font.size, print, info, 1);
671 print(info, ",");
673 print(info, "]");
674 break;
675 case xd_fontchar:
676 print(info, "{\"t\" : %u", op->u.fontchar);
677 break;
678 case xd_style:
679 print(info, "{\"S\" : ");
680 jsonString(op->u.style, print, info);
681 break;
682 case xd_image:
683 print(info, "{\"I\" : [");
684 jsonRect(&op->u.image.pos, print, info);
685 print(info, ",");
687 print(info, "]");
688 break;
689 default: // invalid type; ignore
690 break;
691 }
692 if (more)
693 print(info, "},\n");
694 else
695 print(info, "}\n");
696 agxbfree(&xb);
697}
698
699static void _printXDot(xdot *x, pf print, void *info, print_op ofn) {
700 xdot_op *op;
701 char *base = (char *)(x->ops);
702 for (size_t i = 0; i < x->cnt; i++) {
703 op = (xdot_op *)(base + i * x->sz);
704 ofn(op, print, info, i < x->cnt - 1);
705 }
706}
707
708char *sprintXDot(xdot *x) {
709 agxbuf xb = {0};
711 return agxbdisown(&xb);
712}
713
714void fprintXDot(FILE *fp, xdot *x) {
715 _printXDot(x, (pf)fprintf, fp, printXDot_Op);
716}
717
718void jsonXDot(FILE *fp, xdot *x) {
719 fputs("[\n", fp);
720 _printXDot(x, (pf)fprintf, fp, jsonXDot_Op);
721 fputs("]\n", fp);
722}
723
724static void freeXOpData(xdot_op *x) {
725 switch (x->kind) {
728 free(x->u.polyline.pts);
729 break;
730 case xd_filled_bezier:
732 free(x->u.polyline.pts);
733 break;
734 case xd_polyline:
735 free(x->u.polyline.pts);
736 break;
737 case xd_text:
738 free(x->u.text.text);
739 break;
740 case xd_fill_color:
741 case xd_pen_color:
742 free(x->u.color);
743 break;
747 break;
748 case xd_font:
749 free(x->u.font.name);
750 break;
751 case xd_style:
752 free(x->u.style);
753 break;
754 case xd_image:
755 free(x->u.image.name);
756 break;
757 default:
758 break;
759 }
760}
761
762void freeXDot(xdot *x) {
763 xdot_op *op;
764 char *base;
765 freefunc_t ff = x->freefunc;
766
767 if (!x)
768 return;
769 base = (char *)(x->ops);
770 for (size_t i = 0; i < x->cnt; i++) {
771 op = (xdot_op *)(base + i * x->sz);
772 if (ff)
773 ff(op);
774 freeXOpData(op);
775 }
776 free(base);
777 free(x);
778}
779
781 xdot_op *op;
782 char *base;
783
784 if (!x || !sp)
785 return 1;
786 memset(sp, 0, sizeof(xdot_stats));
787 sp->cnt = x->cnt;
788 base = (char *)(x->ops);
789 for (size_t i = 0; i < x->cnt; i++) {
790 op = (xdot_op *)(base + i * x->sz);
791 switch (op->kind) {
794 sp->n_ellipse++;
795 break;
798 sp->n_polygon++;
799 sp->n_polygon_pts += op->u.polygon.cnt;
800 break;
801 case xd_filled_bezier:
803 sp->n_bezier++;
804 sp->n_bezier_pts += op->u.bezier.cnt;
805 break;
806 case xd_polyline:
807 sp->n_polyline++;
808 sp->n_polyline_pts += op->u.polyline.cnt;
809 break;
810 case xd_text:
811 sp->n_text++;
812 break;
813 case xd_image:
814 sp->n_image++;
815 break;
816 case xd_fill_color:
817 case xd_pen_color:
818 sp->n_color++;
819 break;
822 sp->n_gradcolor++;
823 break;
824 case xd_font:
825 sp->n_font++;
826 break;
827 case xd_fontchar:
828 sp->n_fontchar++;
829 break;
830 case xd_style:
831 sp->n_style++;
832 break;
833 default:
834 break;
835 }
836 }
837
838 return 0;
839}
840
841#define CHK1(s) \
842 if (!s) { \
843 free(stops); \
844 return NULL; \
845 }
846
847/* radGradient:
848 * Parse radial gradient spec
849 * Return NULL on failure.
850 */
851static char *radGradient(char *cp, xdot_color *clr) {
852 char *s = cp;
853 int i;
854 double d;
855 xdot_color_stop *stops = NULL;
856
857 clr->type = xd_radial;
858 s = parseReal(s, &clr->u.ring.x0);
859 CHK1(s);
860 s = parseReal(s, &clr->u.ring.y0);
861 CHK1(s);
862 s = parseReal(s, &clr->u.ring.r0);
863 CHK1(s);
864 s = parseReal(s, &clr->u.ring.x1);
865 CHK1(s);
866 s = parseReal(s, &clr->u.ring.y1);
867 CHK1(s);
868 s = parseReal(s, &clr->u.ring.r1);
869 CHK1(s);
870 s = parseInt(s, &clr->u.ring.n_stops);
871 CHK1(s);
872
873 stops = gv_calloc(clr->u.ring.n_stops, sizeof(stops[0]));
874 for (i = 0; i < clr->u.ring.n_stops; i++) {
875 s = parseReal(s, &d);
876 CHK1(s);
877 stops[i].frac = d;
878 s = parseString(s, &stops[i].color);
879 CHK1(s);
880 }
881 clr->u.ring.stops = stops;
882
883 return cp;
884}
885
886/* linGradient:
887 * Parse linear gradient spec
888 * Return NULL on failure.
889 */
890static char *linGradient(char *cp, xdot_color *clr) {
891 char *s = cp;
892 int i;
893 double d;
894 xdot_color_stop *stops = NULL;
895
896 clr->type = xd_linear;
897 s = parseReal(s, &clr->u.ling.x0);
898 CHK1(s);
899 s = parseReal(s, &clr->u.ling.y0);
900 CHK1(s);
901 s = parseReal(s, &clr->u.ling.x1);
902 CHK1(s);
903 s = parseReal(s, &clr->u.ling.y1);
904 CHK1(s);
905 s = parseInt(s, &clr->u.ling.n_stops);
906 CHK1(s);
907
908 stops = gv_calloc(clr->u.ling.n_stops, sizeof(stops[0]));
909 for (i = 0; i < clr->u.ling.n_stops; i++) {
910 s = parseReal(s, &d);
911 CHK1(s);
912 stops[i].frac = d;
913 s = parseString(s, &stops[i].color);
914 CHK1(s);
915 }
916 clr->u.ling.stops = stops;
917
918 return cp;
919}
920
921/* parseXDotColor:
922 * Parse xdot color spec: ordinary or gradient
923 * The result is stored in clr.
924 * Return NULL on failure.
925 */
926char *parseXDotColor(char *cp, xdot_color *clr) {
927 char c = *cp;
928
929 switch (c) {
930 case '[':
931 return linGradient(cp + 1, clr);
932 case '(':
933 return radGradient(cp + 1, clr);
934 case '#':
935 case '/':
936 clr->type = xd_none;
937 clr->u.clr = cp;
938 return cp;
939 default:
940 if (gv_isalnum(c)) {
941 clr->type = xd_none;
942 clr->u.clr = cp;
943 return cp;
944 }
945 return NULL;
946 }
947}
948
950 int i;
951
952 if (cp->type == xd_linear) {
953 for (i = 0; i < cp->u.ling.n_stops; i++) {
954 free(cp->u.ling.stops[i].color);
955 }
956 free(cp->u.ling.stops);
957 } else if (cp->type == xd_radial) {
958 for (i = 0; i < cp->u.ring.n_stops; i++) {
959 free(cp->u.ring.stops[i].color);
960 }
961 free(cp->u.ring.stops);
962 }
963}
964
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:295
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:345
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
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
static void print(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:109
void free(void *)
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:198
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static bool gv_isspace(int c)
Definition gv_ctype.h:55
static void color(Agraph_t *g)
Definition gvcolor.c:118
agxbuf_trim_zeros(xb)
table Syntax error
Definition htmlparse.y:288
#define PRISIZE_T
Definition prisize_t.h:25
static Ppoint_t * ops
Definition route.c:35
char * style
Definition xdot.h:158
union _xdot_op::@106 u
xdot_font font
Definition xdot.h:157
xdot_polyline polygon
Definition xdot.h:150
xdot_rect ellipse
Definition xdot.h:149
xdot_image image
Definition xdot.h:154
char * color
Definition xdot.h:155
unsigned int fontchar
Definition xdot.h:159
xdot_kind kind
Definition xdot.h:147
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
drawfunc_t drawfunc
Definition xdot.h:161
double frac
Definition xdot.h:49
char * color
Definition xdot.h:50
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::@105 u
double size
Definition xdot.h:104
char * name
Definition xdot.h:105
char * name
Definition xdot.h:100
xdot_rect pos
Definition xdot.h:99
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
double x
Definition xdot.h:79
double z
Definition xdot.h:79
double y
Definition xdot.h:79
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
size_t n_image
Definition xdot.h:187
size_t n_polygon_pts
Definition xdot.h:178
size_t cnt
Definition xdot.h:175
size_t n_text
Definition xdot.h:183
size_t n_style
Definition xdot.h:185
size_t n_polyline_pts
Definition xdot.h:180
size_t n_bezier
Definition xdot.h:181
size_t n_polygon
Definition xdot.h:177
size_t n_fontchar
Definition xdot.h:189
size_t n_font
Definition xdot.h:184
size_t n_polyline
Definition xdot.h:179
size_t n_color
Definition xdot.h:186
size_t n_gradcolor
Definition xdot.h:188
size_t n_ellipse
Definition xdot.h:176
size_t n_bezier_pts
Definition xdot.h:182
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
freefunc_t freefunc
Definition xdot.h:170
xdot_op * ops
Definition xdot.h:169
size_t cnt
Definition xdot.h:167
size_t sz
Definition xdot.h:168
int flags
Definition xdot.h:171
Definition grammar.c:90
#define UNREACHABLE()
Definition unreachable.h:30
static void printAlign(xdot_align a, pf print, void *info)
Definition xdot.c:449
void(* print_op)(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:500
static void printFloat(double f, pf print, void *info, int space)
Definition xdot.c:437
static void jsonXDot_Op(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:611
xdot * parseXDotFOn(char *s, drawfunc_t fns[], size_t sz, xdot *x)
Definition xdot.c:342
static char * linGradient(char *cp, xdot_color *clr)
Definition xdot.c:890
static void printRect(xdot_rect *r, pf print, void *info)
Definition xdot.c:400
static char * parseReal(char *s, double *fp)
Definition xdot.c:23
int(* pf)(void *, char *,...)
Definition xdot.c:398
char * parseXDotColor(char *cp, xdot_color *clr)
Definition xdot.c:926
static char * parseString(char *s, char **sp)
Definition xdot.c:118
static void printXDot_Op(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:502
static void jsonPolyline(xdot_polyline *p, pf print, void *info)
Definition xdot.c:586
#define CHK1(s)
Definition xdot.c:841
int statXDot(xdot *x, xdot_stats *sp)
Definition xdot.c:780
static void printString(char *p, pf print, void *info)
Definition xdot.c:433
void freeXDot(xdot *x)
Definition xdot.c:762
static char * parseRect(char *s, xdot_rect *rp)
Definition xdot.c:55
static char * parseAlign(char *s, xdot_align *ap)
Definition xdot.c:153
#define XDBSIZE
Definition xdot.c:336
static void freeXOpData(xdot_op *x)
Definition xdot.c:724
static void printPolyline(xdot_polyline *p, pf print, void *info)
Definition xdot.c:418
char * sprintXDot(xdot *x)
Definition xdot.c:708
static void jsonString(char *p, pf print, void *info)
Definition xdot.c:596
#define CHK(s)
Definition xdot.c:166
static char * parseInt(char *s, int *ip)
Definition xdot.c:35
void freeXDotColor(xdot_color *cp)
Definition xdot.c:949
void fprintXDot(FILE *fp, xdot *x)
Definition xdot.c:714
static char * parseOp(xdot_op *op, char *s, drawfunc_t ops[], int *error)
Definition xdot.c:172
xdot * parseXDotF(char *s, drawfunc_t fns[], size_t sz)
Definition xdot.c:392
static char * parseUInt(char *s, unsigned int *ip)
Definition xdot.c:45
xdot * parseXDot(char *s)
Definition xdot.c:396
static void _printXDot(xdot *x, pf print, void *info, print_op ofn)
Definition xdot.c:699
static void jsonRect(xdot_rect *r, pf print, void *info)
Definition xdot.c:582
static void toGradString(agxbuf *xb, xdot_color *cp)
Definition xdot.c:465
static char * parsePolyline(char *s, xdot_polyline *pp)
Definition xdot.c:85
static char * radGradient(char *cp, xdot_color *clr)
Definition xdot.c:851
void jsonXDot(FILE *fp, xdot *x)
Definition xdot.c:718
parsing and deparsing of xdot operations
@ xd_none
Definition xdot.h:46
@ xd_radial
Definition xdot.h:46
@ xd_linear
Definition xdot.h:46
struct _xdot_op xdot_op
Definition xdot.h:142
#define XDOT_PARSE_ERROR
Definition xdot.h:164
void(* freefunc_t)(xdot_op *)
Definition xdot.h:144
@ xop_polygon
Definition xdot.h:129
@ xop_font
Definition xdot.h:135
@ xop_image
Definition xdot.h:137
@ xop_bezier
Definition xdot.h:130
@ xop_fill_color
Definition xdot.h:133
@ xop_text
Definition xdot.h:132
@ xop_fontchar
Definition xdot.h:139
@ xop_style
Definition xdot.h:136
@ xop_grad_color
Definition xdot.h:138
@ xop_pen_color
Definition xdot.h:134
@ xop_ellipse
Definition xdot.h:128
@ xop_polyline
Definition xdot.h:131
xdot_align
Definition xdot.h:76
@ xd_left
Definition xdot.h:76
@ xd_right
Definition xdot.h:76
@ xd_center
Definition xdot.h:76
void(* drawfunc_t)(xdot_op *, int)
Definition xdot.h:143
@ 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