Graphviz  2.41.20170921.2350
xdot.c
Go to the documentation of this file.
1 /* vim:set shiftwidth=4 ts=8: */
2 
3 /*************************************************************************
4  * Copyright (c) 2011 AT&T Intellectual Property
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors: See CVS logs. Details at http://www.graphviz.org/
11  *************************************************************************/
12 
13 #include <xdot.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 
18 #define NEW(t) (t*)calloc(1, sizeof(t))
19 #define N_NEW(n,t) (t*)calloc((n), sizeof(t))
20 
21 typedef struct {
22  unsigned char *buf; /* start of buffer */
23  unsigned char *ptr; /* next place to write */
24  unsigned char *eptr; /* end of buffer */
25  int dyna; /* true if buffer is malloc'ed */
26 } agxbuf;
27 
28 #define agxbputc(X,C) ((((X)->ptr >= (X)->eptr) ? agxbmore(X,1) : 0), \
29  (void)(*(X)->ptr++ = ((unsigned char)C)))
30 #define agxbuse(X) (agxbputc(X,'\0'),(char*)((X)->ptr = (X)->buf))
31 
32 static void agxbinit(agxbuf * xb, unsigned int hint, unsigned char *init)
33 {
34  if (init) {
35  xb->buf = init;
36  xb->dyna = 0;
37  } else {
38  if (hint == 0)
39  hint = BUFSIZ;
40  xb->dyna = 1;
41  xb->buf = N_NEW(hint, unsigned char);
42  }
43  xb->eptr = xb->buf + hint;
44  xb->ptr = xb->buf;
45  *xb->ptr = '\0';
46 }
47 static int agxbmore(agxbuf * xb, unsigned int ssz)
48 {
49  int cnt; /* current no. of characters in buffer */
50  int size; /* current buffer size */
51  int nsize; /* new buffer size */
52  unsigned char *nbuf; /* new buffer */
53 
54  size = xb->eptr - xb->buf;
55  nsize = 2 * size;
56  if (size + ssz > nsize)
57  nsize = size + ssz;
58  cnt = xb->ptr - xb->buf;
59  if (xb->dyna) {
60  nbuf = realloc(xb->buf, nsize);
61  } else {
62  nbuf = N_NEW(nsize, unsigned char);
63  memcpy(nbuf, xb->buf, cnt);
64  xb->dyna = 1;
65  }
66  xb->buf = nbuf;
67  xb->ptr = xb->buf + cnt;
68  xb->eptr = xb->buf + nsize;
69  return 0;
70 }
71 
72 static int agxbput(char *s, agxbuf * xb)
73 {
74  unsigned int ssz = strlen(s);
75  if (xb->ptr + ssz > xb->eptr)
76  agxbmore(xb, ssz);
77  memcpy(xb->ptr, s, ssz);
78  xb->ptr += ssz;
79  return ssz;
80 }
81 
82 /* agxbfree:
83  * Free any malloced resources.
84  */
85 static void agxbfree(agxbuf * xb)
86 {
87  if (xb->dyna)
88  free(xb->buf);
89 }
90 
91 /* the parse functions should return NULL on error */
92 static char *parseReal(char *s, double *fp)
93 {
94  char *p;
95  double d;
96 
97  d = strtod(s, &p);
98  if (p == s) return 0;
99 
100  *fp = d;
101  return (p);
102 }
103 
104 
105 static char *parseInt(char *s, int *ip)
106 {
107  char* endp;
108 
109 #ifdef UNUSED
110  r = sscanf(s, "%d%n", ip, &sz);
111  if (r != 1) return 0;
112  else return (s + sz);
113 #endif
114 
115  *ip = (int)strtol (s, &endp, 10);
116  if (s == endp)
117  return 0;
118  else
119  return endp;
120 }
121 
122 static char *parseUInt(char *s, unsigned int *ip)
123 {
124  char* endp;
125 
126  *ip = (unsigned int)strtoul (s, &endp, 10);
127  if (s == endp)
128  return 0;
129  else
130  return endp;
131 }
132 
133 #ifdef UNUSED
134 static char *parsePoint(char *s, xdot_point * pp)
135 {
136  int r, sz;
137  r = sscanf(s, "%lf %lf%n", &(pp->x), &(pp->y), &sz);
138  if (r != 2) return 0;
139  pp->z = 0;
140  return (s + sz);
141 }
142 #endif
143 
144 static char *parseRect(char *s, xdot_rect * rp)
145 {
146  char* endp;
147 #ifdef UNUSED
148  int r, sz;
149  r = sscanf(s, "%lf %lf %lf %lf%n", &(rp->x), &(rp->y), &(rp->w),
150  &(rp->h), &sz);
151  if (r != 4) return 0;
152  else return (s + sz);
153 #endif
154 
155  rp->x = strtod (s, &endp);
156  if (s == endp)
157  return 0;
158  else
159  s = endp;
160 
161  rp->y = strtod (s, &endp);
162  if (s == endp)
163  return 0;
164  else
165  s = endp;
166 
167  rp->w = strtod (s, &endp);
168  if (s == endp)
169  return 0;
170  else
171  s = endp;
172 
173  rp->h = strtod (s, &endp);
174  if (s == endp)
175  return 0;
176  else
177  s = endp;
178 
179  return s;
180 }
181 
182 static char *parsePolyline(char *s, xdot_polyline * pp)
183 {
184  int i;
185  xdot_point *pts;
186  xdot_point *ps;
187  char* endp;
188 
189  s = parseInt(s, &i);
190  if (!s) return s;
191  pts = ps = N_NEW(i, xdot_point);
192  pp->cnt = i;
193  for (i = 0; i < pp->cnt; i++) {
194  ps->x = strtod (s, &endp);
195  if (s == endp) {
196  free (pts);
197  return 0;
198  }
199  else
200  s = endp;
201  ps->y = strtod (s, &endp);
202  if (s == endp) {
203  free (pts);
204  return 0;
205  }
206  else
207  s = endp;
208  ps->z = 0;
209  ps++;
210  }
211  pp->pts = pts;
212  return s;
213 }
214 
215 static char *parseString(char *s, char **sp)
216 {
217  int i;
218  char *c;
219  char *p;
220  s = parseInt(s, &i);
221  if (!s || (i <= 0)) return 0;
222  while (*s && (*s != '-')) s++;
223  if (*s) s++;
224  else {
225  return 0;
226  }
227  c = N_NEW(i + 1, char);
228  p = c;
229  while ((i > 0) && *s) {
230  *p++ = *s++;
231  i--;
232  }
233  if (i > 0) {
234  free (c);
235  return 0;
236  }
237 
238  *p = '\0';
239  *sp = c;
240  return s;
241 }
242 
243 static char *parseAlign(char *s, xdot_align * ap)
244 {
245  int i;
246  s = parseInt(s, &i);
247 
248  if (i < 0)
249  *ap = xd_left;
250  else if (i > 0)
251  *ap = xd_right;
252  else
253  *ap = xd_center;
254  return s;
255 }
256 
257 #define CHK(s) if(!s){*error=1;return 0;}
258 
259 static char *parseOp(xdot_op * op, char *s, drawfunc_t ops[], int* error)
260 {
261  char* cs;
262  xdot_color clr;
263 
264  *error = 0;
265  while (isspace(*s))
266  s++;
267  switch (*s++) {
268  case 'E':
269  op->kind = xd_filled_ellipse;
270  s = parseRect(s, &op->u.ellipse);
271  CHK(s);
272  if (ops)
273  op->drawfunc = ops[xop_ellipse];
274  break;
275 
276  case 'e':
278  s = parseRect(s, &op->u.ellipse);
279  CHK(s);
280  if (ops)
281  op->drawfunc = ops[xop_ellipse];
282  break;
283 
284  case 'P':
285  op->kind = xd_filled_polygon;
286  s = parsePolyline(s, &op->u.polygon);
287  CHK(s);
288  if (ops)
289  op->drawfunc = ops[xop_polygon];
290  break;
291 
292  case 'p':
294  s = parsePolyline(s, &op->u.polygon);
295  CHK(s);
296  if (ops)
297  op->drawfunc = ops[xop_polygon];
298  break;
299 
300  case 'b':
301  op->kind = xd_filled_bezier;
302  s = parsePolyline(s, &op->u.bezier);
303  CHK(s);
304  if (ops)
305  op->drawfunc = ops[xop_bezier];
306  break;
307 
308  case 'B':
309  op->kind = xd_unfilled_bezier;
310  s = parsePolyline(s, &op->u.bezier);
311  CHK(s);
312  if (ops)
313  op->drawfunc = ops[xop_bezier];
314  break;
315 
316  case 'c':
317  s = parseString(s, &cs);
318  CHK(s);
319  cs = parseXDotColor (cs, &clr);
320  CHK(cs);
321  if (clr.type == xd_none) {
322  op->kind = xd_pen_color;
323  op->u.color = clr.u.clr;
324  if (ops)
325  op->drawfunc = ops[xop_pen_color];
326  }
327  else {
328  op->kind = xd_grad_pen_color;
329  op->u.grad_color = clr;
330  if (ops)
331  op->drawfunc = ops[xop_grad_color];
332  }
333  break;
334 
335  case 'C':
336  s = parseString(s, &cs);
337  CHK(s);
338  cs = parseXDotColor (cs, &clr);
339  CHK(cs);
340  if (clr.type == xd_none) {
341  op->kind = xd_fill_color;
342  op->u.color = clr.u.clr;
343  if (ops)
344  op->drawfunc = ops[xop_fill_color];
345  }
346  else {
347  op->kind = xd_grad_fill_color;
348  op->u.grad_color = clr;
349  if (ops)
350  op->drawfunc = ops[xop_grad_color];
351  }
352  break;
353 
354  case 'L':
355  op->kind = xd_polyline;
356  s = parsePolyline(s, &op->u.polyline);
357  CHK(s);
358  if (ops)
359  op->drawfunc = ops[xop_polyline];
360  break;
361 
362  case 'T':
363  op->kind = xd_text;
364  s = parseReal(s, &op->u.text.x);
365  CHK(s);
366  s = parseReal(s, &op->u.text.y);
367  CHK(s);
368  s = parseAlign(s, &op->u.text.align);
369  CHK(s);
370  s = parseReal(s, &op->u.text.width);
371  CHK(s);
372  s = parseString(s, &op->u.text.text);
373  CHK(s);
374  if (ops)
375  op->drawfunc = ops[xop_text];
376  break;
377 
378  case 'F':
379  op->kind = xd_font;
380  s = parseReal(s, &op->u.font.size);
381  CHK(s);
382  s = parseString(s, &op->u.font.name);
383  CHK(s);
384  if (ops)
385  op->drawfunc = ops[xop_font];
386  break;
387 
388  case 'S':
389  op->kind = xd_style;
390  s = parseString(s, &op->u.style);
391  CHK(s);
392  if (ops)
393  op->drawfunc = ops[xop_style];
394  break;
395 
396  case 'I':
397  op->kind = xd_image;
398  s = parseRect(s, &op->u.image.pos);
399  CHK(s);
400  s = parseString(s, &op->u.image.name);
401  CHK(s);
402  if (ops)
403  op->drawfunc = ops[xop_image];
404  break;
405 
406  case 't':
407  op->kind = xd_fontchar;
408  s = parseUInt(s, &op->u.fontchar);
409  CHK(s);
410  if (ops)
411  op->drawfunc = ops[xop_fontchar];
412  break;
413 
414 
415  case '\0':
416  s = 0;
417  break;
418 
419  default:
420  *error = 1;
421  s = 0;
422  break;
423  }
424  return s;
425 }
426 
427 #define XDBSIZE 100
428 
429 /* parseXDotFOn:
430  * Parse and append additional xops onto a given xdot object.
431  * Return x.
432  */
433 xdot *parseXDotFOn (char *s, drawfunc_t fns[], int sz, xdot* x)
434 {
435  xdot_op op;
436  char *ops;
437  int oldsz, bufsz;
438  int error;
439  int initcnt;
440 
441  if (!s)
442  return x;
443 
444  if (!x) {
445  x = NEW(xdot);
446  if (sz <= sizeof(xdot_op))
447  sz = sizeof(xdot_op);
448 
449  /* cnt, freefunc, ops, flags zeroed by NEW */
450  x->sz = sz;
451  }
452  initcnt = x->cnt;
453  sz = x->sz;
454 
455  if (initcnt == 0) {
456  bufsz = XDBSIZE;
457  ops = (char *) calloc(XDBSIZE, sz);
458  }
459  else {
460  ops = (char*)(x->ops);
461  bufsz = initcnt + XDBSIZE;
462  ops = (char *) realloc(ops, bufsz * sz);
463  memset(ops + (initcnt*sz), '\0', (bufsz - initcnt)*sz);
464  }
465 
466  while ((s = parseOp(&op, s, fns, &error))) {
467  if (x->cnt == bufsz) {
468  oldsz = bufsz;
469  bufsz *= 2;
470  ops = (char *) realloc(ops, bufsz * sz);
471  memset(ops + (oldsz*sz), '\0', (bufsz - oldsz)*sz);
472  }
473  *(xdot_op *) (ops + (x->cnt * sz)) = op;
474  x->cnt++;
475  }
476  if (error)
477  x->flags |= XDOT_PARSE_ERROR;
478  if (x->cnt) {
479  x->ops = (xdot_op *) realloc(ops, x->cnt * sz);
480  }
481  else {
482  free (ops);
483  free (x);
484  x = NULL;
485  }
486 
487  return x;
488 
489 }
490 
491 xdot *parseXDotF(char *s, drawfunc_t fns[], int sz)
492 {
493  return parseXDotFOn (s, fns, sz, NULL);
494 }
495 
496 xdot *parseXDot(char *s)
497 {
498  return parseXDotF(s, 0, 0);
499 }
500 
501 typedef void (*pf) (char *, void *);
502 
503 /* trim:
504  * Trailing zeros are removed and decimal point, if possible.
505  */
506 static void trim (char* buf)
507 {
508  char* dotp;
509  char* p;
510 
511  if ((dotp = strchr (buf,'.'))) {
512  p = dotp+1;
513  while (*p) p++; // find end of string
514  p--;
515  while (*p == '0') *p-- = '\0';
516  if (*p == '.') // If all decimals were zeros, remove ".".
517  *p = '\0';
518  else
519  p++;
520  }
521 }
522 
523 static void printRect(xdot_rect * r, pf print, void *info)
524 {
525  char buf[128];
526 
527  sprintf(buf, " %.02f", r->x);
528  trim(buf);
529  print(buf, info);
530  sprintf(buf, " %.02f", r->y);
531  trim(buf);
532  print(buf, info);
533  sprintf(buf, " %.02f", r->w);
534  trim(buf);
535  print(buf, info);
536  sprintf(buf, " %.02f", r->h);
537  trim(buf);
538  print(buf, info);
539 }
540 
541 static void printPolyline(xdot_polyline * p, pf print, void *info)
542 {
543  int i;
544  char buf[512];
545 
546  sprintf(buf, " %d", p->cnt);
547  print(buf, info);
548  for (i = 0; i < p->cnt; i++) {
549  sprintf(buf, " %.02f", p->pts[i].x);
550  trim(buf);
551  print(buf, info);
552  sprintf(buf, " %.02f", p->pts[i].y);
553  trim(buf);
554  print(buf, info);
555  }
556 }
557 
558 static void printString(char *p, pf print, void *info)
559 {
560  char buf[30];
561 
562  sprintf(buf, " %d -", (int) strlen(p));
563  print(buf, info);
564  print(p, info);
565 }
566 
567 static void printInt(int i, pf print, void *info)
568 {
569  char buf[30];
570 
571  sprintf(buf, " %d", i);
572  print(buf, info);
573 }
574 
575 static void printFloat(float f, pf print, void *info, int space)
576 {
577  char buf[128];
578 
579  if (space)
580  sprintf(buf, " %.02f", f);
581  else
582  sprintf(buf, "%.02f", f);
583  trim (buf);
584  print(buf, info);
585 }
586 
587 static void printAlign(xdot_align a, pf print, void *info)
588 {
589  switch (a) {
590  case xd_left:
591  print(" -1", info);
592  break;
593  case xd_right:
594  print(" 1", info);
595  break;
596  case xd_center:
597  print(" 0", info);
598  break;
599  }
600 }
601 
602 static void
603 gradprint (char* s, void* v)
604 {
605  agxbput(s, (agxbuf*)v);
606 }
607 
608 static void
609 toGradString (agxbuf* xb, xdot_color* cp)
610 {
611  int i, n_stops;
612  xdot_color_stop* stops;
613 
614  if (cp->type == xd_linear) {
615  agxbputc (xb, '[');
616  printFloat (cp->u.ling.x0, gradprint, xb, 0);
617  printFloat (cp->u.ling.y0, gradprint, xb, 1);
618  printFloat (cp->u.ling.x1, gradprint, xb, 1);
619  printFloat (cp->u.ling.y1, gradprint, xb, 1);
620  n_stops = cp->u.ling.n_stops;
621  stops = cp->u.ling.stops;
622  }
623  else {
624  agxbputc (xb, '(');
625  printFloat (cp->u.ring.x0, gradprint, xb, 0);
626  printFloat (cp->u.ring.y0, gradprint, xb, 1);
627  printFloat (cp->u.ring.r0, gradprint, xb, 1);
628  printFloat (cp->u.ring.x1, gradprint, xb, 1);
629  printFloat (cp->u.ring.y1, gradprint, xb, 1);
630  printFloat (cp->u.ring.r1, gradprint, xb, 1);
631  n_stops = cp->u.ring.n_stops;
632  stops = cp->u.ring.stops;
633  }
634  printInt (n_stops, gradprint, xb);
635  for (i = 0; i < n_stops; i++) {
636  printFloat (stops[i].frac, gradprint, xb, 1);
637  printString (stops[i].color, gradprint, xb);
638  }
639 
640  if (cp->type == xd_linear)
641  agxbputc (xb, ']');
642  else
643  agxbputc (xb, ')');
644 }
645 
646 typedef void (*print_op)(xdot_op * op, pf print, void *info, int more);
647 
648 static void printXDot_Op(xdot_op * op, pf print, void *info, int more)
649 {
650  agxbuf xb;
651  unsigned char buf[BUFSIZ];
652 
653  agxbinit (&xb, BUFSIZ, buf);
654  switch (op->kind) {
655  case xd_filled_ellipse:
656  print("E", info);
657  printRect(&op->u.ellipse, print, info);
658  break;
659  case xd_unfilled_ellipse:
660  print("e", info);
661  printRect(&op->u.ellipse, print, info);
662  break;
663  case xd_filled_polygon:
664  print("P", info);
665  printPolyline(&op->u.polygon, print, info);
666  break;
667  case xd_unfilled_polygon:
668  print("p", info);
669  printPolyline(&op->u.polygon, print, info);
670  break;
671  case xd_filled_bezier:
672  print("b", info);
673  printPolyline(&op->u.bezier, print, info);
674  break;
675  case xd_unfilled_bezier:
676  print("B", info);
677  printPolyline(&op->u.bezier, print, info);
678  break;
679  case xd_pen_color:
680  print("c", info);
681  printString(op->u.color, print, info);
682  break;
683  case xd_grad_pen_color:
684  print("c", info);
685  toGradString (&xb, &op->u.grad_color);
686  printString(agxbuse(&xb), print, info);
687  break;
688  case xd_fill_color:
689  print("C", info);
690  printString(op->u.color, print, info);
691  break;
692  case xd_grad_fill_color:
693  print("C", info);
694  toGradString (&xb, &op->u.grad_color);
695  printString(agxbuse(&xb), print, info);
696  break;
697  case xd_polyline:
698  print("L", info);
699  printPolyline(&op->u.polyline, print, info);
700  break;
701  case xd_text:
702  print("T", info);
703  printInt(op->u.text.x, print, info);
704  printInt(op->u.text.y, print, info);
705  printAlign(op->u.text.align, print, info);
706  printInt(op->u.text.width, print, info);
707  printString(op->u.text.text, print, info);
708  break;
709  case xd_font:
710  print("F", info);
711  printFloat(op->u.font.size, print, info, 1);
712  printString(op->u.font.name, print, info);
713  break;
714  case xd_fontchar:
715  print("t", info);
716  printInt(op->u.fontchar, print, info);
717  break;
718  case xd_style:
719  print("S", info);
720  printString(op->u.style, print, info);
721  break;
722  case xd_image:
723  print("I", info);
724  printRect(&op->u.image.pos, print, info);
725  printString(op->u.image.name, print, info);
726  break;
727  }
728  if (more)
729  print(" ", info);
730  agxbfree (&xb);
731 }
732 
733 static void jsonRect(xdot_rect * r, pf print, void *info)
734 {
735  char buf[128];
736 
737  sprintf(buf, "[%.06f,%.06f,%.06f,%.06f]", r->x, r->y, r->w, r->h);
738  print(buf, info);
739 }
740 
741 static void jsonPolyline(xdot_polyline * p, pf print, void *info)
742 {
743  int i;
744  char buf[128];
745 
746  print("[", info);
747  for (i = 0; i < p->cnt; i++) {
748  sprintf(buf, "%.06f,%.06f", p->pts[i].x, p->pts[i].y);
749  print(buf, info);
750  if (i < p->cnt-1) print(",", info);
751  }
752  print("]", info);
753 }
754 
755 static void jsonString(char *p, pf print, void *info)
756 {
757  unsigned char c, buf[BUFSIZ];
758  agxbuf xb;
759 
760  agxbinit(&xb, BUFSIZ, buf);
761  agxbputc(&xb, '"');
762  while ((c = *p++)) {
763  if (c == '"') agxbput("\\\"", &xb);
764  else if (c == '\\') agxbput("\\\\", &xb);
765  /* else if (c > 127) handle UTF-8 */
766  else agxbputc(&xb, c);
767  }
768  agxbputc(&xb, '"');
769  print(agxbuse(&xb), info);
770  agxbfree(&xb);
771 }
772 
773 static void jsonXDot_Op(xdot_op * op, pf print, void *info, int more)
774 {
775  agxbuf xb;
776  unsigned char buf[BUFSIZ];
777 
778  agxbinit (&xb, BUFSIZ, buf);
779  switch (op->kind) {
780  case xd_filled_ellipse:
781  print("{E : ", info);
782  jsonRect(&op->u.ellipse, print, info);
783  break;
784  case xd_unfilled_ellipse:
785  print("{e : ", info);
786  jsonRect(&op->u.ellipse, print, info);
787  break;
788  case xd_filled_polygon:
789  print("{P : ", info);
790  jsonPolyline(&op->u.polygon, print, info);
791  break;
792  case xd_unfilled_polygon:
793  print("{p : ", info);
794  jsonPolyline(&op->u.polygon, print, info);
795  break;
796  case xd_filled_bezier:
797  print("{b : ", info);
798  jsonPolyline(&op->u.bezier, print, info);
799  break;
800  case xd_unfilled_bezier:
801  print("{B : ", info);
802  jsonPolyline(&op->u.bezier, print, info);
803  break;
804  case xd_pen_color:
805  print("{c : ", info);
806  jsonString(op->u.color, print, info);
807  break;
808  case xd_grad_pen_color:
809  print("{c : ", info);
810  toGradString (&xb, &op->u.grad_color);
811  jsonString(agxbuse(&xb), print, info);
812  break;
813  case xd_fill_color:
814  print("{C : ", info);
815  jsonString(op->u.color, print, info);
816  break;
817  case xd_grad_fill_color:
818  print("{C : ", info);
819  toGradString (&xb, &op->u.grad_color);
820  jsonString(agxbuse(&xb), print, info);
821  break;
822  case xd_polyline:
823  print("{L :", info);
824  jsonPolyline(&op->u.polyline, print, info);
825  break;
826  case xd_text:
827  print("{T : [", info);
828  printInt(op->u.text.x, print, info);
829  print(",", info);
830  printInt(op->u.text.y, print, info);
831  print(",", info);
832  printAlign(op->u.text.align, print, info);
833  print(",", info);
834  printInt(op->u.text.width, print, info);
835  print(",", info);
836  jsonString(op->u.text.text, print, info);
837  print("]", info);
838  break;
839  case xd_font:
840  print("{F : [", info);
841  op->kind = xd_font;
842  printFloat(op->u.font.size, print, info, 1);
843  print(",", info);
844  jsonString(op->u.font.name, print, info);
845  print("]", info);
846  break;
847  case xd_fontchar:
848  print("{t : ", info);
849  printInt(op->u.fontchar, print, info);
850  break;
851  case xd_style:
852  print("{S : ", info);
853  jsonString(op->u.style, print, info);
854  break;
855  case xd_image:
856  print("{I : [", info);
857  jsonRect(&op->u.image.pos, print, info);
858  print(",", info);
859  jsonString(op->u.image.name, print, info);
860  print("]", info);
861  break;
862  }
863  if (more)
864  print("},\n", info);
865  else
866  print("}\n", info);
867  agxbfree (&xb);
868 }
869 
870 static void _printXDot(xdot * x, pf print, void *info, print_op ofn)
871 {
872  int i;
873  xdot_op *op;
874  char *base = (char *) (x->ops);
875  for (i = 0; i < x->cnt; i++) {
876  op = (xdot_op *) (base + i * x->sz);
877  ofn(op, print, info, (i < x->cnt - 1));
878  }
879 }
880 
881 char *sprintXDot(xdot * x)
882 {
883  char *s;
884  unsigned char buf[BUFSIZ];
885  agxbuf xb;
886  agxbinit(&xb, BUFSIZ, buf);
887  _printXDot(x, (pf) agxbput, &xb, printXDot_Op);
888  s = strdup(agxbuse(&xb));
889  agxbfree(&xb);
890 
891  return s;
892 }
893 
894 void fprintXDot(FILE * fp, xdot * x)
895 {
896  _printXDot(x, (pf) fputs, fp, printXDot_Op);
897 }
898 
899 void jsonXDot(FILE * fp, xdot * x)
900 {
901  fputs ("[\n", fp);
902  _printXDot(x, (pf) fputs, fp, jsonXDot_Op);
903  fputs ("]\n", fp);
904 }
905 
906 static void freeXOpData(xdot_op * x)
907 {
908  switch (x->kind) {
909  case xd_filled_polygon:
910  case xd_unfilled_polygon:
911  free(x->u.polyline.pts);
912  break;
913  case xd_filled_bezier:
914  case xd_unfilled_bezier:
915  free(x->u.polyline.pts);
916  break;
917  case xd_polyline:
918  free(x->u.polyline.pts);
919  break;
920  case xd_text:
921  free(x->u.text.text);
922  break;
923  case xd_fill_color:
924  case xd_pen_color:
925  free(x->u.color);
926  break;
927  case xd_grad_fill_color:
928  case xd_grad_pen_color:
929  freeXDotColor (&x->u.grad_color);
930  break;
931  case xd_font:
932  free(x->u.font.name);
933  break;
934  case xd_style:
935  free(x->u.style);
936  break;
937  case xd_image:
938  free(x->u.image.name);
939  break;
940  default:
941  break;
942  }
943 }
944 
945 void freeXDot (xdot * x)
946 {
947  int i;
948  xdot_op *op;
949  char *base;
950  freefunc_t ff = x->freefunc;
951 
952  if (!x) return;
953  base = (char *) (x->ops);
954  for (i = 0; i < x->cnt; i++) {
955  op = (xdot_op *) (base + i * x->sz);
956  if (ff) ff (op);
957  freeXOpData(op);
958  }
959  free(base);
960  free(x);
961 }
962 
963 int statXDot (xdot* x, xdot_stats* sp)
964 {
965  int i;
966  xdot_op *op;
967  char *base;
968 
969  if (!x || !sp) return 1;
970  memset(sp, 0, sizeof(xdot_stats));
971  sp->cnt = x->cnt;
972  base = (char *) (x->ops);
973  for (i = 0; i < x->cnt; i++) {
974  op = (xdot_op *) (base + i * x->sz);
975  switch (op->kind) {
976  case xd_filled_ellipse:
977  case xd_unfilled_ellipse:
978  sp->n_ellipse++;
979  break;
980  case xd_filled_polygon:
981  case xd_unfilled_polygon:
982  sp->n_polygon++;
983  sp->n_polygon_pts += op->u.polygon.cnt;
984  break;
985  case xd_filled_bezier:
986  case xd_unfilled_bezier:
987  sp->n_bezier++;
988  sp->n_bezier_pts += op->u.bezier.cnt;
989  break;
990  case xd_polyline:
991  sp->n_polyline++;
992  sp->n_polyline_pts += op->u.polyline.cnt;
993  break;
994  case xd_text:
995  sp->n_text++;
996  break;
997  case xd_image:
998  sp->n_image++;
999  break;
1000  case xd_fill_color:
1001  case xd_pen_color:
1002  sp->n_color++;
1003  break;
1004  case xd_grad_fill_color:
1005  case xd_grad_pen_color:
1006  sp->n_gradcolor++;
1007  break;
1008  case xd_font:
1009  sp->n_font++;
1010  break;
1011  case xd_fontchar:
1012  sp->n_fontchar++;
1013  break;
1014  case xd_style:
1015  sp->n_style++;
1016  break;
1017  default :
1018  break;
1019  }
1020  }
1021 
1022  return 0;
1023 }
1024 
1026 colorType (char* cp)
1027 {
1028  xdot_grad_type rv;
1029 
1030  switch (*cp) {
1031  case '[' :
1032  rv = xd_linear;
1033  break;
1034  case '(' :
1035  rv = xd_radial;
1036  break;
1037  default :
1038  rv = xd_none;
1039  break;
1040  }
1041  return rv;
1042 }
1043 
1044 #define CHK1(s) if(!s){free(stops);return NULL;}
1045 
1046 /* radGradient:
1047  * Parse radial gradient spec
1048  * Return NULL on failure.
1049  */
1050 static char*
1051 radGradient (char* cp, xdot_color* clr)
1052 {
1053  char* s = cp;
1054  int i;
1055  double d;
1056  xdot_color_stop* stops = NULL;
1057 
1058  clr->type = xd_radial;
1059  s = parseReal(s, &clr->u.ring.x0);
1060  CHK1(s);
1061  s = parseReal(s, &clr->u.ring.y0);
1062  CHK1(s);
1063  s = parseReal(s, &clr->u.ring.r0);
1064  CHK1(s);
1065  s = parseReal(s, &clr->u.ring.x1);
1066  CHK1(s);
1067  s = parseReal(s, &clr->u.ring.y1);
1068  CHK1(s);
1069  s = parseReal(s, &clr->u.ring.r1);
1070  CHK1(s);
1071  s = parseInt(s, &clr->u.ring.n_stops);
1072  CHK1(s);
1073 
1074  stops = N_NEW(clr->u.ring.n_stops,xdot_color_stop);
1075  for (i = 0; i < clr->u.ring.n_stops; i++) {
1076  s = parseReal(s, &d);
1077  CHK1(s);
1078  stops[i].frac = d;
1079  s = parseString(s, &stops[i].color);
1080  CHK1(s);
1081  }
1082  clr->u.ring.stops = stops;
1083 
1084  return cp;
1085 }
1086 
1087 /* linGradient:
1088  * Parse linear gradient spec
1089  * Return NULL on failure.
1090  */
1091 static char*
1092 linGradient (char* cp, xdot_color* clr)
1093 {
1094  char* s = cp;
1095  int i;
1096  double d;
1097  xdot_color_stop* stops = NULL;
1098 
1099  clr->type = xd_linear;
1100  s = parseReal(s, &clr->u.ling.x0);
1101  CHK1(s);
1102  s = parseReal(s, &clr->u.ling.y0);
1103  CHK1(s);
1104  s = parseReal(s, &clr->u.ling.x1);
1105  CHK1(s);
1106  s = parseReal(s, &clr->u.ling.y1);
1107  CHK1(s);
1108  s = parseInt(s, &clr->u.ling.n_stops);
1109  CHK1(s);
1110 
1111  stops = N_NEW(clr->u.ling.n_stops,xdot_color_stop);
1112  for (i = 0; i < clr->u.ling.n_stops; i++) {
1113  s = parseReal(s, &d);
1114  CHK1(s);
1115  stops[i].frac = d;
1116  s = parseString(s, &stops[i].color);
1117  CHK1(s);
1118  }
1119  clr->u.ling.stops = stops;
1120 
1121  return cp;
1122 }
1123 
1124 /* parseXDotColor:
1125  * Parse xdot color spec: ordinary or gradient
1126  * The result is stored in clr.
1127  * Return NULL on failure.
1128  */
1129 char*
1130 parseXDotColor (char* cp, xdot_color* clr)
1131 {
1132  char c = *cp;
1133 
1134  switch (c) {
1135  case '[' :
1136  return linGradient (cp+1, clr);
1137  break;
1138  case '(' :
1139  return radGradient (cp+1, clr);
1140  break;
1141  case '#' :
1142  case '/' :
1143  clr->type = xd_none;
1144  clr->u.clr = cp;
1145  return cp;
1146  break;
1147  default :
1148  if (isalnum(c)) {
1149  clr->type = xd_none;
1150  clr->u.clr = cp;
1151  return cp;
1152  }
1153  else
1154  return NULL;
1155  }
1156 }
1157 
1159 {
1160  int i;
1161 
1162  if (cp->type == xd_linear) {
1163  for (i = 0; i < cp->u.ling.n_stops; i++) {
1164  free (cp->u.ling.stops[i].color);
1165  }
1166  free (cp->u.ling.stops);
1167  }
1168  else if (cp->type == xd_radial) {
1169  for (i = 0; i < cp->u.ring.n_stops; i++) {
1170  free (cp->u.ring.stops[i].color);
1171  }
1172  free (cp->u.ring.stops);
1173  }
1174 }
1175 
1176 #if 0
1177 static void execOp(xdot_op * op, int param)
1178 {
1179  op->drawfunc(op, param);
1180 }
1181 #endif
xdot_linear_grad ling
Definition: xdot.h:65
double r0
Definition: xdot.h:55
int n_bezier
Definition: xdot.h:163
unsigned char * buf
Definition: agxbuf.h:35
int n_color
Definition: xdot.h:168
xdot_color grad_color
Definition: xdot.h:138
int n_gradcolor
Definition: xdot.h:170
Definition: xdot.h:38
double y0
Definition: xdot.h:48
#define XDBSIZE
Definition: xdot.c:427
union _xdot_op::@54 u
int n_bezier_pts
Definition: xdot.h:164
int statXDot(xdot *x, xdot_stats *sp)
Definition: xdot.c:963
int flags
Definition: xdot.h:153
int n_fontchar
Definition: xdot.h:171
int cnt
Definition: xdot.h:157
Definition: xdot.h:78
double size
Definition: xdot.h:100
char * text
Definition: xdot.h:91
Definition: xdot.h:109
xdot_color_stop * stops
Definition: xdot.h:58
int sz
Definition: xdot.h:150
int n_stops
Definition: xdot.h:50
xdot_polyline bezier
Definition: xdot.h:134
Definition: xdot.h:71
Definition: xdot.h:39
xdot_color_stop * stops
Definition: xdot.h:51
char * name
Definition: xdot.h:101
freefunc_t freefunc
Definition: xdot.h:152
char * color
Definition: xdot.h:44
size_t agxbput(agxbuf *xb, const char *s)
Definition: agxbuf.c:84
Definition: xdot.h:108
void(* freefunc_t)(xdot_op *)
Definition: xdot.h:126
Definition: xdot.h:71
Definition: xdot.h:71
int n_font
Definition: xdot.h:166
Definition: xdot.h:128
double x0
Definition: xdot.h:55
int dyna
Definition: agxbuf.h:38
double x
Definition: xdot.h:79
xdot_grad_type type
Definition: xdot.h:62
xdot_rect ellipse
Definition: xdot.h:131
char * clr
Definition: xdot.h:64
double x1
Definition: xdot.h:49
char * sprintXDot(xdot *x)
Definition: xdot.c:881
void(* print_op)(xdot_op *op, pf print, void *info, int more)
Definition: xdot.c:646
xdot * parseXDot(char *s)
Definition: xdot.c:496
double y1
Definition: xdot.h:49
xdot_kind kind
Definition: xdot.h:129
unsigned char * eptr
Definition: agxbuf.h:37
#define agxbputc(X, C)
Definition: xdot.c:28
#define CHK1(s)
Definition: xdot.c:1044
double w
Definition: xdot.h:79
Definition: xdot.h:119
double z
Definition: xdot.h:75
double y
Definition: xdot.h:75
int n_ellipse
Definition: xdot.h:158
double h
Definition: xdot.h:79
char * parseXDotColor(char *cp, xdot_color *clr)
Definition: xdot.c:1130
Definition: xdot.h:148
char * style
Definition: xdot.h:140
int
Definition: grammar.c:1264
xdot_image image
Definition: xdot.h:136
Definition: xdot.h:109
char * color
Definition: xdot.h:137
void fprintXDot(FILE *fp, xdot *x)
Definition: xdot.c:894
int n_polygon_pts
Definition: xdot.h:160
int n_style
Definition: xdot.h:167
#define CHK(s)
Definition: xdot.c:257
unsigned int fontchar
Definition: xdot.h:141
int n_stops
Definition: xdot.h:57
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
Definition: agxbuf.c:25
xdot_rect pos
Definition: xdot.h:95
double y
Definition: xdot.h:79
Definition: grammar.c:79
xdot_grad_type colorType(char *cp)
Definition: xdot.c:1026
double y0
Definition: xdot.h:55
double width
Definition: xdot.h:90
double x
Definition: xdot.h:75
int n_image
Definition: xdot.h:169
int n_polygon
Definition: xdot.h:159
xdot * parseXDotF(char *s, drawfunc_t fns[], int sz)
Definition: xdot.c:491
int cnt
Definition: xdot.h:83
xdot_radial_grad ring
Definition: xdot.h:66
#define NULL
Definition: logic.h:39
int cnt
Definition: xdot.h:149
xdot_op * ops
Definition: xdot.h:151
xdot_grad_type
Definition: xdot.h:36
float frac
Definition: xdot.h:43
double x1
Definition: xdot.h:56
char * name
Definition: xdot.h:96
#define XDOT_PARSE_ERROR
Definition: xdot.h:146
double x
Definition: xdot.h:88
void jsonXDot(FILE *fp, xdot *x)
Definition: xdot.c:899
Definition: xdot.h:118
struct _xdot_op xdot_op
Definition: xdot.h:124
xdot_align
Definition: xdot.h:70
void(* drawfunc_t)(xdot_op *, int)
Definition: xdot.h:125
xdot_point * pts
Definition: xdot.h:84
void(* pf)(char *, void *)
Definition: xdot.c:501
#define agxbuse(X)
Definition: xdot.c:30
#define N_NEW(n, t)
Definition: xdot.c:19
void freeXDot(xdot *x)
Definition: xdot.c:945
xdot_polyline polygon
Definition: xdot.h:132
xdot_text text
Definition: xdot.h:135
Definition: agxbuf.h:34
double y
Definition: xdot.h:88
xdot_align align
Definition: xdot.h:89
double y1
Definition: xdot.h:56
Definition: xdot.h:37
int n_polyline_pts
Definition: xdot.h:162
#define NEW(t)
Definition: xdot.c:18
union xdot_color::@53 u
unsigned char * ptr
Definition: agxbuf.h:36
int n_text
Definition: xdot.h:165
drawfunc_t drawfunc
Definition: xdot.h:143
double x0
Definition: xdot.h:48
void agxbfree(agxbuf *xb)
Definition: agxbuf.c:94
xdot_polyline polyline
Definition: xdot.h:133
int n_polyline
Definition: xdot.h:161
double r1
Definition: xdot.h:56
void freeXDotColor(xdot_color *cp)
Definition: xdot.c:1158
xdot * parseXDotFOn(char *s, drawfunc_t fns[], int sz, xdot *x)
Definition: xdot.c:433
Definition: xdot.h:109
int agxbmore(agxbuf *xb, size_t ssz)
Definition: agxbuf.c:44
xdot_font font
Definition: xdot.h:139