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