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