Graphviz  2.41.20171026.1811
gvrender_core_pic.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include "config.h"
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdarg.h>
19 #include <ctype.h>
20 
21 #include "gvplugin_render.h"
22 #include "gvplugin_device.h"
23 #include "gvio.h"
24 #include "agxbuf.h"
25 #include "utils.h"
26 #include "color.h"
27 #include "colorprocs.h"
28 
29 #include "const.h"
30 
31 /* Number of points to split splines into */
32 #define BEZIERSUBDIVISION 6
33 
34 #define PIC_COORDS_PER_LINE (16) /* to avoid stdio BUF overflow */
35 
36 typedef enum { FORMAT_PIC, } format_type;
37 
38 static int onetime = TRUE;
39 static double Fontscale;
40 
41 /* There are a couple of ways to generate output:
42  1. generate for whatever size is given by the bounding box
43  - the drawing at its "natural" size might not fit on a physical page
44  ~ dot size specification can be used to scale the drawing
45  ~ and it's not difficult for user to scale the pic output to fit (multiply 4 (3 distinct) numbers on 3 lines by a scale factor)
46  - some troff implementations may clip large graphs
47  ~ handle by scaling to manageable size
48  - give explicit width and height as parameters to .PS
49  - pic scale variable is reset to 1.0
50  - fonts are printed as size specified by caller, modified by user scaling
51  2. scale to fit on a physical page
52  - requires an assumption of page size (GNU pic assumes 8.5x11.0 inches)
53  ~ any assumption is bound to be wrong more often than right
54  - requires separate scaling of font point sizes since pic's scale variable doesn't affect text
55  ~ possible, as above
56  - likewise for line thickness
57  - GNU pic does this (except for fonts) if .PS is used without explicit width or height; DWB pic does not
58  ~ pic variants likely to cause trouble
59  The first approach is used here.
60 */
61 
62 static const char *EscComment = ".\\\" "; /* troff comment */
63 static const char picgen_msghdr[] = "dot pic plugin: ";
64 
65 static void unsupported(char *s)
66 {
67  agerr(AGWARN, "%s%s unsupported\n", picgen_msghdr, s);
68 }
69 
70 /* troff font mapping */
71 typedef struct {
72  char trname[3], *psname;
73 } fontinfo;
74 
75 static fontinfo fonttab[] = {
76  {"AB", "AvantGarde-Demi"},
77  {"AI", "AvantGarde-BookOblique"},
78  {"AR", "AvantGarde-Book"},
79  {"AX", "AvantGarde-DemiOblique"},
80  {"B ", "Times-Bold"},
81  {"BI", "Times-BoldItalic"},
82  {"CB", "Courier-Bold"},
83  {"CO", "Courier"},
84  {"CX", "Courier-BoldOblique"},
85  {"H ", "Helvetica"},
86  {"HB", "Helvetica-Bold"},
87  {"HI", "Helvetica-Oblique"},
88  {"HX", "Helvetica-BoldOblique"},
89  {"Hb", "Helvetica-Narrow-Bold"},
90  {"Hi", "Helvetica-Narrow-Oblique"},
91  {"Hr", "Helvetica-Narrow"},
92  {"Hx", "Helvetica-Narrow-BoldOblique"},
93  {"I ", "Times-Italic"},
94  {"KB", "Bookman-Demi"},
95  {"KI", "Bookman-LightItalic"},
96  {"KR", "Bookman-Light"},
97  {"KX", "Bookman-DemiItalic"},
98  {"NB", "NewCenturySchlbk-Bold"},
99  {"NI", "NewCenturySchlbk-Italic"},
100  {"NR", "NewCenturySchlbk-Roman"},
101  {"NX", "NewCenturySchlbk-BoldItalic"},
102  {"PA", "Palatino-Roman"},
103  {"PB", "Palatino-Bold"},
104  {"PI", "Palatino-Italic"},
105  {"PX", "Palatino-BoldItalic"},
106  {"R ", "Times-Roman"},
107  {"S ", "Symbol"},
108  {"ZD", "ZapfDingbats"},
109  {"\000\000", (char *) 0}
110 };
111 
112 static char *picfontname(char *psname)
113 {
114  char *rv;
115  fontinfo *p;
116 
117  for (p = fonttab; p->psname; p++)
118  if (strcmp(p->psname, psname) == 0)
119  break;
120  if (p->psname)
121  rv = p->trname;
122  else {
123  agerr(AGERR, "%s%s is not a troff font\n", picgen_msghdr, psname);
124  /* try base font names, e.g. Helvetica-Outline-Oblique -> Helvetica-Outline -> Helvetica */
125  if ((rv = strrchr(psname, '-'))) {
126  *rv = '\0'; /* psname is not specified as const ... */
127  rv = picfontname(psname);
128  } else
129  rv = "R";
130  }
131  return rv;
132 }
133 
134 static void picptarray(GVJ_t *job, pointf * A, int n, int close)
135 {
136  int i;
137  point p;
138 
139  for (i = 0; i < n; i++) {
140  PF2P(A[i],p);
141  gvprintf(job, " %d %d", p.x, p.y);
142  }
143  if (close) {
144  PF2P(A[0],p);
145  gvprintf(job, " %d %d", p.x, p.y);
146  }
147  gvputs(job, "\n");
148 }
149 
150 static char *pic_string(char *s)
151 {
152  static char *buf = NULL;
153  static int bufsize = 0;
154  int pos = 0;
155  char *p;
156  unsigned char c;
157 
158  if (!buf) {
159  bufsize = 64;
160  buf = malloc(bufsize * sizeof(char));
161  }
162 
163  p = buf;
164  while ((c = *s++)) {
165  if (pos > (bufsize - 8)) {
166  bufsize *= 2;
167  buf = realloc(buf, bufsize * sizeof(char));
168  p = buf + pos;
169  }
170  if (isascii(c)) {
171  if (c == '\\') {
172  *p++ = '\\';
173  pos++;
174  }
175  *p++ = c;
176  pos++;
177  } else {
178  *p++ = '\\';
179  sprintf(p, "%03o", c);
180  p += 3;
181  pos += 4;
182  }
183  }
184  *p = '\0';
185  return buf;
186 }
187 
188 static void pic_line_style(obj_state_t *obj, int *line_style, double *style_val)
189 {
190  switch (obj->pen) {
191  case PEN_DASHED:
192  *line_style = 1;
193  *style_val = 10.;
194  break;
195  case PEN_DOTTED:
196  *line_style = 2;
197  *style_val = 10.;
198  break;
199  case PEN_SOLID:
200  default:
201  *line_style = 0;
202  *style_val = 0.;
203  break;
204  }
205 }
206 
207 static void pic_comment(GVJ_t *job, char *str)
208 {
209  gvprintf(job, "%s %s\n", EscComment, str);
210 }
211 
212 static void pic_begin_graph(GVJ_t * job)
213 {
214  obj_state_t *obj = job->obj;
215 
216  gvprintf(job, "%s Creator: %s version %s (%s)\n",
217  EscComment, job->common->info[0], job->common->info[1], job->common->info[2]);
218  gvprintf(job, "%s Title: %s\n", EscComment, agnameof(obj->u.g));
219  gvprintf(job,
220  "%s save point size and font\n.nr .S \\n(.s\n.nr DF \\n(.f\n",
221  EscComment);
222 }
223 
224 static void pic_end_graph(GVJ_t * job)
225 {
226  gvprintf(job,
227  "%s restore point size and font\n.ps \\n(.S\n.ft \\n(DF\n",
228  EscComment);
229 }
230 
231 static void pic_begin_page(GVJ_t * job)
232 {
233  box pbr = job->pageBoundingBox;
234  double height, width;
235 
236  if (onetime && job->rotation && (job->rotation != 90)) {
237  unsupported("rotation");
238  onetime = FALSE;
239  }
240  height = PS2INCH((double) (pbr.UR.y) - (double) (pbr.LL.y));
241  width = PS2INCH((double) (pbr.UR.x) - (double) (pbr.LL.x));
242  if (job->rotation == 90) {
243  double temp = width;
244  width = height;
245  height = temp;
246  }
247  gvprintf(job, ".PS %.5f %.5f\n", width, height);
248  gvprintf(job,
249  "%s to change drawing size, multiply the width and height on the .PS line above and the number on the two lines below (rounded to the nearest integer) by a scale factor\n",
250  EscComment);
251  if (width > 0.0) {
252  Fontscale = log10(width);
253  Fontscale += 3.0 - (int) Fontscale; /* between 3.0 and 4.0 */
254  } else
255  Fontscale = 3.0;
256  Fontscale = pow(10.0, Fontscale); /* a power of 10 times width, between 1000 and 10000 */
257  gvprintf(job, ".nr SF %.0f\nscalethickness = %.0f\n", Fontscale,
258  Fontscale);
259  gvprintf(job,
260  "%s don't change anything below this line in this drawing\n",
261  EscComment);
262  gvprintf(job,
263  "%s non-fatal run-time pic version determination, version 2\n",
264  EscComment);
265  gvprintf(job,
266  "boxrad=2.0 %s will be reset to 0.0 by gpic only\n",
267  EscComment);
268  gvprintf(job, "scale=1.0 %s required for comparisons\n",
269  EscComment);
270  gvprintf(job,
271  "%s boxrad is now 0.0 in gpic, else it remains 2.0\n",
272  EscComment);
273  gvprintf(job,
274  "%s dashwid is 0.1 in 10th Edition, 0.05 in DWB 2 and in gpic\n",
275  EscComment);
276  gvprintf(job,
277  "%s fillval is 0.3 in 10th Edition (fill 0 means black), 0.5 in gpic (fill 0 means white), undefined in DWB 2\n",
278  EscComment);
279  gvprintf(job,
280  "%s fill has no meaning in DWB 2, gpic can use fill or filled, 10th Edition uses fill only\n",
281  EscComment);
282  gvprintf(job,
283  "%s DWB 2 doesn't use fill and doesn't define fillval\n",
284  EscComment);
285  gvprintf(job,
286  "%s reset works in gpic and 10th edition, but isn't defined in DWB 2\n",
287  EscComment);
288  gvprintf(job, "%s DWB 2 compatibility definitions\n",
289  EscComment);
290  gvprintf(job,
291  "if boxrad > 1.0 && dashwid < 0.075 then X\n\tfillval = 1;\n\tdefine fill Y Y;\n\tdefine solid Y Y;\n\tdefine reset Y scale=1.0 Y;\nX\n");
292  gvprintf(job, "reset %s set to known state\n", EscComment);
293  gvprintf(job, "%s GNU pic vs. 10th Edition d\\(e'tente\n",
294  EscComment);
295  gvprintf(job,
296  "if fillval > 0.4 then X\n\tdefine setfillval Y fillval = 1 - Y;\n\tdefine bold Y thickness 2 Y;\n");
297  gvprintf(job,
298  "\t%s if you use gpic and it barfs on encountering \"solid\",\n",
299  EscComment);
300  gvprintf(job,
301  "\t%s\tinstall a more recent version of gpic or switch to DWB or 10th Edition pic;\n",
302  EscComment);
303  gvprintf(job,
304  "\t%s\tsorry, the groff folks changed gpic; send any complaint to them;\n",
305  EscComment);
306  gvprintf(job,
307  "X else Z\n\tdefine setfillval Y fillval = Y;\n\tdefine bold Y Y;\n\tdefine filled Y fill Y;\nZ\n");
308  gvprintf(job,
309  "%s arrowhead has no meaning in DWB 2, arrowhead = 7 makes filled arrowheads in gpic and in 10th Edition\n",
310  EscComment);
311  gvprintf(job,
312  "%s arrowhead is undefined in DWB 2, initially 1 in gpic, 2 in 10th Edition\n",
313  EscComment);
314  gvprintf(job, "arrowhead = 7 %s not used by graphviz\n",
315  EscComment);
316  gvprintf(job,
317  "%s GNU pic supports a boxrad variable to draw boxes with rounded corners; DWB and 10th Ed. do not\n",
318  EscComment);
319  gvprintf(job, "boxrad = 0 %s no rounded corners in graphviz\n",
320  EscComment);
321  gvprintf(job,
322  "%s GNU pic supports a linethick variable to set line thickness; DWB and 10th Ed. do not\n",
323  EscComment);
324  gvprintf(job, "linethick = 0; oldlinethick = linethick\n");
325  gvprintf(job,
326  "%s .PS w/o args causes GNU pic to scale drawing to fit 8.5x11 paper; DWB does not\n",
327  EscComment);
328  gvprintf(job,
329  "%s maxpsht and maxpswid have no meaning in DWB 2.0, set page boundaries in gpic and in 10th Edition\n",
330  EscComment);
331  gvprintf(job,
332  "%s maxpsht and maxpswid are predefined to 11.0 and 8.5 in gpic\n",
333  EscComment);
334  gvprintf(job, "maxpsht = %f\nmaxpswid = %f\n", height, width);
335  gvprintf(job, "Dot: [\n");
336  gvprintf(job,
337  "define attrs0 %% %%; define unfilled %% %%; define rounded %% %%; define diagonals %% %%\n");
338 }
339 
340 static void pic_end_page(GVJ_t * job)
341 {
342  gvprintf(job,
343  "]\n.PE\n");
344 }
345 
346 static void pic_textspan(GVJ_t * job, pointf p, textspan_t * span)
347 {
348  static char *lastname;
349  static int lastsize;
350  int sz;
351 
352  switch (span->just) {
353  case 'l':
354  break;
355  case 'r':
356  p.x -= span->size.x;
357  break;
358  default:
359  case 'n':
360  p.x -= span->size.x / 2;
361  break;
362  }
363  /* Why on earth would we do this. But it works. SCN 2/26/2002 */
364  p.y += span->font->size / (3.0 * POINTS_PER_INCH);
365  p.x += span->size.x / (2.0 * POINTS_PER_INCH);
366 
367  if (span->font->name && (!(lastname) || strcmp(lastname, span->font->name))) {
368  gvprintf(job, ".ft %s\n", picfontname(span->font->name));
369  lastname = span->font->name;
370  }
371  if ((sz = (int)span->font->size) < 1)
372  sz = 1;
373  if (sz != lastsize) {
374  gvprintf(job, ".ps %d*\\n(SFu/%.0fu\n", sz, Fontscale);
375  lastsize = sz;
376  }
377  gvprintf(job, "\"%s\" at (%.5f,%.5f);\n",
378  pic_string(span->str), p.x, p.y);
379 }
380 
381 static void pic_ellipse(GVJ_t * job, pointf * A, int filled)
382 {
383  /* A[] contains 2 points: the center and corner. */
384 
385  gvprintf(job,
386  "ellipse attrs%d %swid %.5f ht %.5f at (%.5f,%.5f);\n", 1,
387  filled ? "fill " : "",
388  PS2INCH(2*(A[1].x - A[0].x)),
389  PS2INCH(2*(A[1].y - A[0].y)),
390  PS2INCH(A[0].x),
391  PS2INCH(A[0].y));
392 }
393 
394 static void pic_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
395 // start_y, end_x, end_y);
396  int arrow_at_end, int filled)
397 {
398  obj_state_t *obj = job->obj;
399 
400 // int object_code = 3; /* always 3 for spline */
401  int sub_type;
402  int line_style; /* solid, dotted, dashed */
403 // int thickness = obj->penwidth;
404 // int pen_color = obj->pencolor.u.index;
405  int fill_color = obj->fillcolor.u.index;
406 // int pen_style = 0; /* not used */
407  int area_fill;
408  double style_val;
409 // int cap_style = 0;
410 // int forward_arrow = 0;
411 // int backward_arrow = 0;
412  int npoints = n;
413  int i;
414 
415  pointf pf, V[4];
416  point p;
417  int j, step;
418  int count = 0;
419  int size;
420 
421  char *buffer;
422  char *buf;
423  buffer =
424  malloc((npoints + 1) * (BEZIERSUBDIVISION +
425  1) * 20 * sizeof(char));
426  buf = buffer;
427 
428  pic_line_style(obj, &line_style, &style_val);
429 
430  if (filled) {
431  sub_type = 5; /* closed X-spline */
432  area_fill = 20; /* fully saturated color */
433  fill_color = job->obj->fillcolor.u.index;
434  }
435  else {
436  sub_type = 4; /* opened X-spline */
437  area_fill = -1;
438  fill_color = 0;
439  }
440  V[3].x = A[0].x;
441  V[3].y = A[0].y;
442  /* Write first point in line */
443  count++;
444  PF2P(A[0], p);
445  size = sprintf(buf, " %d %d", p.x, p.y);
446  buf += size;
447  /* write subsequent points */
448  for (i = 0; i + 3 < n; i += 3) {
449  V[0] = V[3];
450  for (j = 1; j <= 3; j++) {
451  V[j].x = A[i + j].x;
452  V[j].y = A[i + j].y;
453  }
454  for (step = 1; step <= BEZIERSUBDIVISION; step++) {
455  count++;
456  pf = Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
457  PF2P(pf, p);
458  size = sprintf(buf, " %d %d", p.x, p.y);
459  buf += size;
460  }
461  }
462 
463 // gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d\n",
464 // object_code,
465 // sub_type,
466 // line_style,
467 // thickness,
468 // pen_color,
469 // fill_color,
470 // depth,
471 // pen_style,
472 // area_fill,
473 // style_val, cap_style, forward_arrow, backward_arrow, count);
474 
475  gvprintf(job, " %s\n", buffer); /* print points */
476  free(buffer);
477  for (i = 0; i < count; i++) {
478  gvprintf(job, " %d", i % (count - 1) ? 1 : 0); /* -1 on all */
479  }
480  gvputs(job, "\n");
481 }
482 
483 static void pic_polygon(GVJ_t * job, pointf * A, int n, int filled)
484 {
485  obj_state_t *obj = job->obj;
486 
487 // int object_code = 2; /* always 2 for polyline */
488 // int sub_type = 3; /* always 3 for polygon */
489  int line_style; /* solid, dotted, dashed */
490 // int thickness = obj->penwidth;
491 // int pen_color = obj->pencolor.u.index;
492 // int fill_color = obj->fillcolor.u.index;
493 // int pen_style = 0; /* not used */
494 // int area_fill = filled ? 20 : -1;
495  double style_val;
496 // int join_style = 0;
497 // int cap_style = 0;
498 // int radius = 0;
499 // int forward_arrow = 0;
500 // int backward_arrow = 0;
501 // int npoints = n + 1;
502 
503  pic_line_style(obj, &line_style, &style_val);
504 
505 // gvprintf(job,
506 // "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
507 // object_code, sub_type, line_style, thickness, pen_color,
508 // fill_color, depth, pen_style, area_fill, style_val, join_style,
509 // cap_style, radius, forward_arrow, backward_arrow, npoints);
510  picptarray(job, A, n, 1); /* closed shape */
511 }
512 
513 static void pic_polyline(GVJ_t * job, pointf * A, int n)
514 {
515  obj_state_t *obj = job->obj;
516 
517 // int object_code = 2; /* always 2 for polyline */
518 // int sub_type = 1; /* always 1 for polyline */
519  int line_style; /* solid, dotted, dashed */
520 // int thickness = obj->penwidth;
521 // int pen_color = obj->pencolor.u.index;
522 // int fill_color = 0;
523 // int pen_style = 0; /* not used */
524 // int area_fill = 0;
525  double style_val;
526 // int join_style = 0;
527 // int cap_style = 0;
528 // int radius = 0;
529 // int forward_arrow = 0;
530 // int backward_arrow = 0;
531 // int npoints = n;
532 
533  pic_line_style(obj, &line_style, &style_val);
534 
535 // gvprintf(job,
536 // "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n",
537 // object_code, sub_type, line_style, thickness, pen_color,
538 // fill_color, depth, pen_style, area_fill, style_val, join_style,
539 // cap_style, radius, forward_arrow, backward_arrow, npoints);
540  picptarray(job, A, n, 0); /* open shape */
541 }
542 
544  0, /* pic_begin_job */
545  0, /* pic_end_job */
546  pic_begin_graph,
547  pic_end_graph,
548  0, /* pic_begin_layer */
549  0, /* pic_end_layer */
550  pic_begin_page,
551  pic_end_page,
552  0, /* pic_begin_cluster */
553  0, /* pic_end_cluster */
554  0, /* pic_begin_nodes */
555  0, /* pic_end_nodes */
556  0, /* pic_begin_edges */
557  0, /* pic_end_edges */
558  0, /* pic_begin_node */
559  0, /* pic_end_node */
560  0, /* pic_begin_edge */
561  0, /* pic_end_edge */
562  0, /* pic_begin_anchor */
563  0, /* pic_end_anchor */
564  0, /* pic_begin_label */
565  0, /* pic_end_label */
566  pic_textspan,
567  0, /* pic_resolve_color */
568  pic_ellipse,
569  pic_polygon,
570  pic_bezier,
571  pic_polyline,
572  pic_comment,
573  0, /* pic_library_shape */
574 };
575 
576 
577 static gvrender_features_t render_features_pic = {
578  0, /* flags */
579  4., /* default pad - graph units */
580  NULL, /* knowncolors */
581  0, /* sizeof knowncolors */
582  HSVA_DOUBLE, /* color_type */
583 };
584 
585 static gvdevice_features_t device_features_pic = {
586  0, /* flags */
587  {0.,0.}, /* default margin - points */
588  {0.,0.}, /* default page width, height - points */
589  {72.,72.}, /* default dpi */
590 };
591 
593  {FORMAT_PIC, "pic", -1, &pic_engine, &render_features_pic},
594  {0, NULL, 0, NULL, NULL}
595 };
596 
598  {FORMAT_PIC, "pic:pic", -1, NULL, &device_features_pic},
599  {0, NULL, 0, NULL, NULL}
600 };
pointf size
Definition: textspan.h:64
Definition: cgraph.h:388
int rotation
Definition: gvcjob.h:328
union color_s::@10 u
pen_type pen
Definition: gvcjob.h:206
int index
Definition: color.h:42
double size
Definition: textspan.h:52
char * psname
Definition: picgen.c:81
Definition: geom.h:28
#define PF2P(pf, p)
Definition: geom.h:72
gvrender_engine_t pic_engine
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
Definition: gvcjob.h:271
char * name
Definition: textspan.h:49
point UR
Definition: geom.h:33
int x
Definition: geom.h:26
gvplugin_installed_t gvrender_pic_types[]
#define POINTS_PER_INCH
Definition: geom.h:62
Definition: cgraph.h:388
obj_state_t * obj
Definition: gvcjob.h:278
#define PS2INCH(a_points)
Definition: geom.h:69
int gvputs(GVJ_t *job, const char *s)
Definition: gvdevice.c:270
box pageBoundingBox
Definition: gvcjob.h:338
char * str
Definition: textspan.h:59
int
Definition: grammar.c:1264
char trname[3]
Definition: picgen.c:81
double y
Definition: geom.h:28
CGRAPH_API char * agnameof(void *)
Definition: id.c:143
GVCOMMON_t * common
Definition: gvcjob.h:276
char ** info
Definition: gvcommon.h:22
point LL
Definition: geom.h:33
Definition: grammar.c:79
graph_t * g
Definition: gvcjob.h:195
format_type
#define BEZIERSUBDIVISION
pointf Bezier(pointf *V, int degree, double t, pointf *Left, pointf *Right)
Definition: utils.c:221
#define NULL
Definition: logic.h:39
Definition: geom.h:26
double x
Definition: geom.h:28
char just
Definition: textspan.h:65
union obj_state_s::@23 u
void(* pf)(char *, void *)
Definition: xdot.c:501
agxbuf * str
Definition: htmlparse.c:85
gvcolor_t fillcolor
Definition: gvcjob.h:203
int y
Definition: geom.h:26
#define FALSE
Definition: cgraph.h:35
gvplugin_installed_t gvdevice_pic_types[]
void gvprintf(GVJ_t *job, const char *format,...)
Definition: gvdevice.c:389
textfont_t * font
Definition: textspan.h:60
Definition: geom.h:33
#define TRUE
Definition: cgraph.h:38