Graphviz 12.0.1~dev.20240716.0800
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 <cgraph/agxbuf.h>
12#include <cgraph/alloc.h>
13#include <cgraph/gv_ctype.h>
14#include <cgraph/prisize_t.h>
15#include <cgraph/unreachable.h>
16#include <xdot/xdot.h>
17#include <stdlib.h>
18#include <string.h>
19
20/* the parse functions should return NULL on error */
21static char *parseReal(char *s, double *fp)
22{
23 char *p;
24 double d;
25
26 d = strtod(s, &p);
27 if (p == s) return 0;
28
29 *fp = d;
30 return (p);
31}
32
33
34static char *parseInt(char *s, int *ip)
35{
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{
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{
58 char* endp;
59
60 rp->x = strtod (s, &endp);
61 if (s == endp)
62 return 0;
63 else
64 s = endp;
65
66 rp->y = strtod (s, &endp);
67 if (s == endp)
68 return 0;
69 else
70 s = endp;
71
72 rp->w = strtod (s, &endp);
73 if (s == endp)
74 return 0;
75 else
76 s = endp;
77
78 rp->h = strtod (s, &endp);
79 if (s == endp)
80 return 0;
81 else
82 s = endp;
83
84 return s;
85}
86
87static char *parsePolyline(char *s, xdot_polyline * pp)
88{
89 unsigned i;
90 xdot_point *pts;
92 char* endp;
93
94 s = parseUInt(s, &i);
95 if (!s) return NULL;
96 pts = ps = gv_calloc(i, sizeof(ps[0]));
97 pp->cnt = i;
98 for (i = 0; i < pp->cnt; i++) {
99 ps->x = strtod (s, &endp);
100 if (s == endp) {
101 free (pts);
102 return NULL;
103 }
104 else
105 s = endp;
106 ps->y = strtod (s, &endp);
107 if (s == endp) {
108 free (pts);
109 return NULL;
110 }
111 else
112 s = endp;
113 ps->z = 0;
114 ps++;
115 }
116 pp->pts = pts;
117 return s;
118}
119
120static char *parseString(char *s, char **sp)
121{
122 int i;
123 s = parseInt(s, &i);
124 if (!s || i <= 0) return 0;
125 while (*s && *s != '-') s++;
126 if (*s) 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{
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) if(!s){*error=1;return 0;}
168
169static char *parseOp(xdot_op * op, char *s, drawfunc_t ops[], int* error)
170{
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 }
237 else {
239 op->u.grad_color = clr;
240 if (ops)
242 }
243 break;
244
245 case 'C':
246 s = parseString(s, &cs);
247 CHK(s);
248 cs = parseXDotColor (cs, &clr);
249 CHK(cs);
250 if (clr.type == xd_none) {
251 op->kind = xd_fill_color;
252 op->u.color = clr.u.clr;
253 if (ops)
255 }
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
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 }
367 else {
368 bufsz = initcnt + XDBSIZE;
369 ops = gv_recalloc(x->ops, initcnt, bufsz, sz);
370 }
371
372 while ((s = parseOp(&op, s, fns, &error))) {
373 if (x->cnt == bufsz) {
374 oldsz = bufsz;
375 bufsz *= 2;
376 ops = gv_recalloc(ops, oldsz, bufsz, sz);
377 }
378 *(xdot_op *) (ops + x->cnt * sz) = op;
379 x->cnt++;
380 }
381 if (error)
383 if (x->cnt) {
384 x->ops = gv_recalloc(ops, bufsz, x->cnt, sz);
385 }
386 else {
387 free (ops);
388 free (x);
389 x = NULL;
390 }
391
392 return x;
393
394}
395
396xdot *parseXDotF(char *s, drawfunc_t fns[], size_t sz) {
397 return parseXDotFOn (s, fns, sz, NULL);
398}
399
401{
402 return parseXDotF(s, 0, 0);
403}
404
405typedef int (*pf)(void*, char*, ...);
406
407static void printRect(xdot_rect * r, pf print, void *info)
408{
409 agxbuf buf = {0};
410
411 agxbprint(&buf, " %.02f", r->x);
412 agxbuf_trim_zeros(&buf);
413 print(info, "%s", agxbuse(&buf));
414 agxbprint(&buf, " %.02f", r->y);
415 agxbuf_trim_zeros(&buf);
416 print(info, "%s", agxbuse(&buf));
417 agxbprint(&buf, " %.02f", r->w);
418 agxbuf_trim_zeros(&buf);
419 print(info, "%s", agxbuse(&buf));
420 agxbprint(&buf, " %.02f", r->h);
421 agxbuf_trim_zeros(&buf);
422 print(info, "%s", agxbuse(&buf));
423 agxbfree(&buf);
424}
425
426static void printPolyline(xdot_polyline * p, pf print, void *info)
427{
428 agxbuf buf = {0};
429
430 print(info, " %" PRISIZE_T, p->cnt);
431 for (size_t i = 0; i < p->cnt; i++) {
432 agxbprint(&buf, " %.02f", p->pts[i].x);
433 agxbuf_trim_zeros(&buf);
434 print(info, "%s", agxbuse(&buf));
435 agxbprint(&buf, " %.02f", p->pts[i].y);
436 agxbuf_trim_zeros(&buf);
437 print(info, "%s", agxbuse(&buf));
438 }
439 agxbfree(&buf);
440}
441
442static void printString(char *p, pf print, void *info)
443{
444 print(info, " %" PRISIZE_T " -%s", strlen(p), p);
445}
446
447static void printFloat(double f, pf print, void *info, int space) {
448 agxbuf buf = {0};
449
450 if (space)
451 agxbprint(&buf, " %.02f", f);
452 else
453 agxbprint(&buf, "%.02f", f);
454 agxbuf_trim_zeros(&buf);
455 print(info, "%s", agxbuse(&buf));
456 agxbfree(&buf);
457}
458
459static void printAlign(xdot_align a, pf print, void *info)
460{
461 switch (a) {
462 case xd_left:
463 print(info, " -1");
464 break;
465 case xd_right:
466 print(info, " 1");
467 break;
468 case xd_center:
469 print(info, " 0");
470 break;
471 default:
472 UNREACHABLE();
473 }
474}
475
476static void
478{
479 int i, n_stops;
480 xdot_color_stop* stops;
481
482 if (cp->type == xd_linear) {
483 agxbputc (xb, '[');
484 printFloat (cp->u.ling.x0, (pf)agxbprint, xb, 0);
485 printFloat (cp->u.ling.y0, (pf)agxbprint, xb, 1);
486 printFloat (cp->u.ling.x1, (pf)agxbprint, xb, 1);
487 printFloat (cp->u.ling.y1, (pf)agxbprint, xb, 1);
488 n_stops = cp->u.ling.n_stops;
489 stops = cp->u.ling.stops;
490 }
491 else {
492 agxbputc (xb, '(');
493 printFloat (cp->u.ring.x0, (pf)agxbprint, xb, 0);
494 printFloat (cp->u.ring.y0, (pf)agxbprint, xb, 1);
495 printFloat (cp->u.ring.r0, (pf)agxbprint, xb, 1);
496 printFloat (cp->u.ring.x1, (pf)agxbprint, xb, 1);
497 printFloat (cp->u.ring.y1, (pf)agxbprint, xb, 1);
498 printFloat (cp->u.ring.r1, (pf)agxbprint, xb, 1);
499 n_stops = cp->u.ring.n_stops;
500 stops = cp->u.ring.stops;
501 }
502 agxbprint(xb, " %d", n_stops);
503 for (i = 0; i < n_stops; i++) {
504 printFloat (stops[i].frac, (pf)agxbprint, xb, 1);
505 printString (stops[i].color, (pf)agxbprint, xb);
506 }
507
508 if (cp->type == xd_linear)
509 agxbputc (xb, ']');
510 else
511 agxbputc (xb, ')');
512}
513
514typedef void (*print_op)(xdot_op * op, pf print, void *info, int more);
515
516static void printXDot_Op(xdot_op * op, pf print, void *info, int more)
517{
518 agxbuf xb = {0};
519 switch (op->kind) {
521 print(info, "E");
522 printRect(&op->u.ellipse, print, info);
523 break;
525 print(info, "e");
526 printRect(&op->u.ellipse, print, info);
527 break;
529 print(info, "P");
531 break;
533 print(info, "p");
535 break;
536 case xd_filled_bezier:
537 print(info, "b");
539 break;
541 print(info, "B");
543 break;
544 case xd_pen_color:
545 print(info, "c");
547 break;
549 print(info, "c");
550 toGradString (&xb, &op->u.grad_color);
552 break;
553 case xd_fill_color:
554 print(info, "C");
556 break;
558 print(info, "C");
559 toGradString (&xb, &op->u.grad_color);
561 break;
562 case xd_polyline:
563 print(info, "L");
565 break;
566 case xd_text:
567 print(info, "T %.f %.f", op->u.text.x, op->u.text.y);
569 print(info, " %.f", op->u.text.width);
571 break;
572 case xd_font:
573 print(info, "F");
574 printFloat(op->u.font.size, print, info, 1);
576 break;
577 case xd_fontchar:
578 print(info, "t %u", op->u.fontchar);
579 break;
580 case xd_style:
581 print(info, "S");
583 break;
584 case xd_image:
585 print(info, "I");
586 printRect(&op->u.image.pos, print, info);
588 break;
589 default: // invalid type; ignore
590 break;
591 }
592 if (more)
593 print(info, " ");
594 agxbfree (&xb);
595}
596
597static void jsonRect(xdot_rect * r, pf print, void *info)
598{
599 print(info, "[%.06f,%.06f,%.06f,%.06f]", r->x, r->y, r->w, r->h);
600}
601
602static void jsonPolyline(xdot_polyline * p, pf print, void *info)
603{
604 print(info, "[");
605 for (size_t i = 0; i < p->cnt; i++) {
606 print(info, "%.06f,%.06f", p->pts[i].x, p->pts[i].y);
607 if (i < p->cnt-1) print(info, ",");
608 }
609 print(info, "]");
610}
611
612static void jsonString(char *p, pf print, void *info)
613{
614 char c;
615
616 print(info, "\"");
617 while ((c = *p++)) {
618 if (c == '"') print(info, "\\\"");
619 else if (c == '\\') print(info, "\\\\");
620 else print(info, "%c", c);
621 }
622 print(info, "\"");
623}
624
625static void jsonXDot_Op(xdot_op * op, pf print, void *info, int more)
626{
627 agxbuf xb = {0};
628 switch (op->kind) {
630 print(info, "{\"E\" : ");
631 jsonRect(&op->u.ellipse, print, info);
632 break;
634 print(info, "{\"e\" : ");
635 jsonRect(&op->u.ellipse, print, info);
636 break;
638 print(info, "{\"P\" : ");
640 break;
642 print(info, "{\"p\" : ");
644 break;
645 case xd_filled_bezier:
646 print(info, "{\"b\" : ");
648 break;
650 print(info, "{\"B\" : ");
652 break;
653 case xd_pen_color:
654 print(info, "{\"c\" : ");
655 jsonString(op->u.color, print, info);
656 break;
658 print(info, "{\"c\" : ");
659 toGradString (&xb, &op->u.grad_color);
661 break;
662 case xd_fill_color:
663 print(info, "{\"C\" : ");
664 jsonString(op->u.color, print, info);
665 break;
667 print(info, "{\"C\" : ");
668 toGradString (&xb, &op->u.grad_color);
670 break;
671 case xd_polyline:
672 print(info, "{\"L\" :");
674 break;
675 case xd_text:
676 print(info, "{\"T\" : [ %.f, %.f,", op->u.text.x, op->u.text.y);
678 print(info, ", %.f,", op->u.text.width);
680 print(info, "]");
681 break;
682 case xd_font:
683 print(info, "{\"F\" : [");
684 op->kind = xd_font;
685 printFloat(op->u.font.size, print, info, 1);
686 print(info, ",");
688 print(info, "]");
689 break;
690 case xd_fontchar:
691 print(info, "{\"t\" : %u", op->u.fontchar);
692 break;
693 case xd_style:
694 print(info, "{\"S\" : ");
695 jsonString(op->u.style, print, info);
696 break;
697 case xd_image:
698 print(info, "{\"I\" : [");
699 jsonRect(&op->u.image.pos, print, info);
700 print(info, ",");
702 print(info, "]");
703 break;
704 default: // invalid type; ignore
705 break;
706 }
707 if (more)
708 print(info, "},\n");
709 else
710 print(info, "}\n");
711 agxbfree (&xb);
712}
713
714static void _printXDot(xdot * x, pf print, void *info, print_op ofn)
715{
716 xdot_op *op;
717 char *base = (char *) (x->ops);
718 for (size_t i = 0; i < x->cnt; i++) {
719 op = (xdot_op *) (base + i * x->sz);
720 ofn(op, print, info, i < x->cnt - 1);
721 }
722}
723
724char *sprintXDot(xdot * x)
725{
726 agxbuf xb = {0};
728 return agxbdisown(&xb);
729}
730
731void fprintXDot(FILE * fp, xdot * x)
732{
733 _printXDot(x, (pf)fprintf, fp, printXDot_Op);
734}
735
736void jsonXDot(FILE * fp, xdot * x)
737{
738 fputs ("[\n", fp);
739 _printXDot(x, (pf)fprintf, fp, jsonXDot_Op);
740 fputs ("]\n", fp);
741}
742
743static void freeXOpData(xdot_op * x)
744{
745 switch (x->kind) {
748 free(x->u.polyline.pts);
749 break;
750 case xd_filled_bezier:
752 free(x->u.polyline.pts);
753 break;
754 case xd_polyline:
755 free(x->u.polyline.pts);
756 break;
757 case xd_text:
758 free(x->u.text.text);
759 break;
760 case xd_fill_color:
761 case xd_pen_color:
762 free(x->u.color);
763 break;
767 break;
768 case xd_font:
769 free(x->u.font.name);
770 break;
771 case xd_style:
772 free(x->u.style);
773 break;
774 case xd_image:
775 free(x->u.image.name);
776 break;
777 default:
778 break;
779 }
780}
781
782void freeXDot (xdot * x)
783{
784 xdot_op *op;
785 char *base;
786 freefunc_t ff = x->freefunc;
787
788 if (!x) return;
789 base = (char *) (x->ops);
790 for (size_t i = 0; i < x->cnt; i++) {
791 op = (xdot_op *) (base + i * x->sz);
792 if (ff) ff (op);
793 freeXOpData(op);
794 }
795 free(base);
796 free(x);
797}
798
800{
801 xdot_op *op;
802 char *base;
803
804 if (!x || !sp) return 1;
805 memset(sp, 0, sizeof(xdot_stats));
806 sp->cnt = x->cnt;
807 base = (char *) (x->ops);
808 for (size_t i = 0; i < x->cnt; i++) {
809 op = (xdot_op *) (base + i * x->sz);
810 switch (op->kind) {
813 sp->n_ellipse++;
814 break;
817 sp->n_polygon++;
818 sp->n_polygon_pts += op->u.polygon.cnt;
819 break;
820 case xd_filled_bezier:
822 sp->n_bezier++;
823 sp->n_bezier_pts += op->u.bezier.cnt;
824 break;
825 case xd_polyline:
826 sp->n_polyline++;
827 sp->n_polyline_pts += op->u.polyline.cnt;
828 break;
829 case xd_text:
830 sp->n_text++;
831 break;
832 case xd_image:
833 sp->n_image++;
834 break;
835 case xd_fill_color:
836 case xd_pen_color:
837 sp->n_color++;
838 break;
841 sp->n_gradcolor++;
842 break;
843 case xd_font:
844 sp->n_font++;
845 break;
846 case xd_fontchar:
847 sp->n_fontchar++;
848 break;
849 case xd_style:
850 sp->n_style++;
851 break;
852 default :
853 break;
854 }
855 }
856
857 return 0;
858}
859
860#define CHK1(s) if(!s){free(stops);return NULL;}
861
862/* radGradient:
863 * Parse radial gradient spec
864 * Return NULL on failure.
865 */
866static char*
867radGradient (char* cp, xdot_color* clr)
868{
869 char* s = cp;
870 int i;
871 double d;
872 xdot_color_stop* stops = NULL;
873
874 clr->type = xd_radial;
875 s = parseReal(s, &clr->u.ring.x0);
876 CHK1(s);
877 s = parseReal(s, &clr->u.ring.y0);
878 CHK1(s);
879 s = parseReal(s, &clr->u.ring.r0);
880 CHK1(s);
881 s = parseReal(s, &clr->u.ring.x1);
882 CHK1(s);
883 s = parseReal(s, &clr->u.ring.y1);
884 CHK1(s);
885 s = parseReal(s, &clr->u.ring.r1);
886 CHK1(s);
887 s = parseInt(s, &clr->u.ring.n_stops);
888 CHK1(s);
889
890 stops = gv_calloc(clr->u.ring.n_stops, sizeof(stops[0]));
891 for (i = 0; i < clr->u.ring.n_stops; i++) {
892 s = parseReal(s, &d);
893 CHK1(s);
894 stops[i].frac = d;
895 s = parseString(s, &stops[i].color);
896 CHK1(s);
897 }
898 clr->u.ring.stops = stops;
899
900 return cp;
901}
902
903/* linGradient:
904 * Parse linear gradient spec
905 * Return NULL on failure.
906 */
907static char*
908linGradient (char* cp, xdot_color* clr)
909{
910 char* s = cp;
911 int i;
912 double d;
913 xdot_color_stop* stops = NULL;
914
915 clr->type = xd_linear;
916 s = parseReal(s, &clr->u.ling.x0);
917 CHK1(s);
918 s = parseReal(s, &clr->u.ling.y0);
919 CHK1(s);
920 s = parseReal(s, &clr->u.ling.x1);
921 CHK1(s);
922 s = parseReal(s, &clr->u.ling.y1);
923 CHK1(s);
924 s = parseInt(s, &clr->u.ling.n_stops);
925 CHK1(s);
926
927 stops = gv_calloc(clr->u.ling.n_stops, sizeof(stops[0]));
928 for (i = 0; i < clr->u.ling.n_stops; i++) {
929 s = parseReal(s, &d);
930 CHK1(s);
931 stops[i].frac = d;
932 s = parseString(s, &stops[i].color);
933 CHK1(s);
934 }
935 clr->u.ling.stops = stops;
936
937 return cp;
938}
939
940/* parseXDotColor:
941 * Parse xdot color spec: ordinary or gradient
942 * The result is stored in clr.
943 * Return NULL on failure.
944 */
945char*
947{
948 char c = *cp;
949
950 switch (c) {
951 case '[' :
952 return linGradient (cp+1, clr);
953 break;
954 case '(' :
955 return radGradient (cp+1, clr);
956 break;
957 case '#' :
958 case '/' :
959 clr->type = xd_none;
960 clr->u.clr = cp;
961 return cp;
962 break;
963 default :
964 if (gv_isalnum(c)) {
965 clr->type = xd_none;
966 clr->u.clr = cp;
967 return cp;
968 }
969 else
970 return NULL;
971 }
972}
973
975{
976 int i;
977
978 if (cp->type == xd_linear) {
979 for (i = 0; i < cp->u.ling.n_stops; i++) {
980 free (cp->u.ling.stops[i].color);
981 }
982 free (cp->u.ling.stops);
983 }
984 else if (cp->type == xd_radial) {
985 for (i = 0; i < cp->u.ring.n_stops; i++) {
986 free (cp->u.ring.stops[i].color);
987 }
988 free (cp->u.ring.stops);
989 }
990}
991
static void agxbuf_trim_zeros(agxbuf *xb)
Definition agxbuf.h:336
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:77
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:213
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:256
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
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
void error(int level, const char *s,...)
Definition error.c:83
static void print(Excc_t *cc, Exnode_t *exnode)
Definition excc.c:125
void free(void *)
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
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:128
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:147
xdot_font font
Definition xdot.h:146
xdot_polyline polygon
Definition xdot.h:139
xdot_rect ellipse
Definition xdot.h:138
xdot_image image
Definition xdot.h:143
char * color
Definition xdot.h:144
unsigned int fontchar
Definition xdot.h:148
xdot_kind kind
Definition xdot.h:136
xdot_text text
Definition xdot.h:142
xdot_polyline bezier
Definition xdot.h:141
xdot_polyline polyline
Definition xdot.h:140
xdot_color grad_color
Definition xdot.h:145
drawfunc_t drawfunc
Definition xdot.h:150
union _xdot_op::@126 u
char * color
Definition xdot.h:51
float frac
Definition xdot.h:50
xdot_grad_type type
Definition xdot.h:69
xdot_linear_grad ling
Definition xdot.h:72
xdot_radial_grad ring
Definition xdot.h:73
union xdot_color::@125 u
char * clr
Definition xdot.h:71
double size
Definition xdot.h:107
char * name
Definition xdot.h:108
char * name
Definition xdot.h:103
xdot_rect pos
Definition xdot.h:102
double y1
Definition xdot.h:56
xdot_color_stop * stops
Definition xdot.h:58
double y0
Definition xdot.h:55
double x0
Definition xdot.h:55
double x1
Definition xdot.h:56
double x
Definition xdot.h:82
double y
Definition xdot.h:82
size_t cnt
Definition xdot.h:90
xdot_point * pts
Definition xdot.h:91
double r0
Definition xdot.h:62
double x0
Definition xdot.h:62
double y0
Definition xdot.h:62
double x1
Definition xdot.h:63
double y1
Definition xdot.h:63
double r1
Definition xdot.h:63
xdot_color_stop * stops
Definition xdot.h:65
double x
Definition xdot.h:86
double w
Definition xdot.h:86
double y
Definition xdot.h:86
double h
Definition xdot.h:86
size_t n_image
Definition xdot.h:176
size_t n_polygon_pts
Definition xdot.h:167
size_t cnt
Definition xdot.h:164
size_t n_text
Definition xdot.h:172
size_t n_style
Definition xdot.h:174
size_t n_polyline_pts
Definition xdot.h:169
size_t n_bezier
Definition xdot.h:170
size_t n_polygon
Definition xdot.h:166
size_t n_fontchar
Definition xdot.h:178
size_t n_font
Definition xdot.h:173
size_t n_polyline
Definition xdot.h:168
size_t n_color
Definition xdot.h:175
size_t n_gradcolor
Definition xdot.h:177
size_t n_ellipse
Definition xdot.h:165
size_t n_bezier_pts
Definition xdot.h:171
double width
Definition xdot.h:97
char * text
Definition xdot.h:98
double x
Definition xdot.h:95
xdot_align align
Definition xdot.h:96
double y
Definition xdot.h:95
Definition xdot.h:155
freefunc_t freefunc
Definition xdot.h:159
xdot_op * ops
Definition xdot.h:158
size_t cnt
Definition xdot.h:156
size_t sz
Definition xdot.h:157
int flags
Definition xdot.h:160
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30
static void printAlign(xdot_align a, pf print, void *info)
Definition xdot.c:459
void(* print_op)(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:514
static void printFloat(double f, pf print, void *info, int space)
Definition xdot.c:447
static void jsonXDot_Op(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:625
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:908
static void printRect(xdot_rect *r, pf print, void *info)
Definition xdot.c:407
static char * parseReal(char *s, double *fp)
Definition xdot.c:21
int(* pf)(void *, char *,...)
Definition xdot.c:405
char * parseXDotColor(char *cp, xdot_color *clr)
Definition xdot.c:946
static char * parseString(char *s, char **sp)
Definition xdot.c:120
static void printXDot_Op(xdot_op *op, pf print, void *info, int more)
Definition xdot.c:516
static void jsonPolyline(xdot_polyline *p, pf print, void *info)
Definition xdot.c:602
#define CHK1(s)
Definition xdot.c:860
int statXDot(xdot *x, xdot_stats *sp)
Definition xdot.c:799
static void printString(char *p, pf print, void *info)
Definition xdot.c:442
void freeXDot(xdot *x)
Definition xdot.c:782
static char * parseRect(char *s, xdot_rect *rp)
Definition xdot.c:56
static char * parseAlign(char *s, xdot_align *ap)
Definition xdot.c:153
#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:426
char * sprintXDot(xdot *x)
Definition xdot.c:724
static void jsonString(char *p, pf print, void *info)
Definition xdot.c:612
#define CHK(s)
Definition xdot.c:167
static char * parseInt(char *s, int *ip)
Definition xdot.c:34
void freeXDotColor(xdot_color *cp)
Definition xdot.c:974
void fprintXDot(FILE *fp, xdot *x)
Definition xdot.c:731
static char * parseOp(xdot_op *op, char *s, drawfunc_t ops[], int *error)
Definition xdot.c:169
xdot * parseXDotF(char *s, drawfunc_t fns[], size_t sz)
Definition xdot.c:396
static char * parseUInt(char *s, unsigned int *ip)
Definition xdot.c:45
xdot * parseXDot(char *s)
Definition xdot.c:400
static void _printXDot(xdot *x, pf print, void *info, print_op ofn)
Definition xdot.c:714
static void jsonRect(xdot_rect *r, pf print, void *info)
Definition xdot.c:597
static void toGradString(agxbuf *xb, xdot_color *cp)
Definition xdot.c:477
static char * parsePolyline(char *s, xdot_polyline *pp)
Definition xdot.c:87
static char * radGradient(char *cp, xdot_color *clr)
Definition xdot.c:867
void jsonXDot(FILE *fp, xdot *x)
Definition xdot.c:736
parsing and deparsing of xdot operations
@ xd_none
Definition xdot.h:44
@ xd_radial
Definition xdot.h:46
@ xd_linear
Definition xdot.h:45
struct _xdot_op xdot_op
Definition xdot.h:131
#define XDOT_PARSE_ERROR
Definition xdot.h:153
void(* freefunc_t)(xdot_op *)
Definition xdot.h:133
@ xop_polygon
Definition xdot.h:123
@ xop_font
Definition xdot.h:126
@ xop_image
Definition xdot.h:126
@ xop_bezier
Definition xdot.h:124
@ xop_fill_color
Definition xdot.h:126
@ xop_text
Definition xdot.h:125
@ xop_fontchar
Definition xdot.h:128
@ xop_style
Definition xdot.h:126
@ xop_grad_color
Definition xdot.h:127
@ xop_pen_color
Definition xdot.h:126
@ xop_ellipse
Definition xdot.h:122
@ xop_polyline
Definition xdot.h:125
xdot_align
Definition xdot.h:77
@ xd_left
Definition xdot.h:78
@ xd_right
Definition xdot.h:78
@ xd_center
Definition xdot.h:78
void(* drawfunc_t)(xdot_op *, int)
Definition xdot.h:132
@ xd_filled_polygon
Definition xdot.h:113
@ xd_pen_color
Definition xdot.h:116
@ xd_unfilled_ellipse
Definition xdot.h:112
@ xd_fontchar
Definition xdot.h:118
@ xd_font
Definition xdot.h:116
@ xd_fill_color
Definition xdot.h:116
@ xd_unfilled_bezier
Definition xdot.h:114
@ xd_grad_fill_color
Definition xdot.h:117
@ xd_polyline
Definition xdot.h:115
@ xd_text
Definition xdot.h:115
@ xd_filled_ellipse
Definition xdot.h:112
@ xd_image
Definition xdot.h:116
@ xd_unfilled_polygon
Definition xdot.h:113
@ xd_grad_pen_color
Definition xdot.h:117
@ xd_filled_bezier
Definition xdot.h:114
@ xd_style
Definition xdot.h:116