1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file defines the initialization for any generic Plotter object,
20 including both private data and public methods. There is a one-to-one
21 correspondence between public methods and user-callable functions in the
22 C API. */
23
24 #include "sys-defines.h"
25 #include "extern.h"
26
27 /* additional include files for DJGPP */
28 #ifdef MSDOS
29 #include <io.h> /* for setmode() */
30 #include <fcntl.h> /* for O_BINARY */
31 #include <unistd.h> /* for isatty() */
32 #endif
33
34 /* global library variables (user-settable error handlers) */
35 #ifndef LIBPLOTTER
36 int (*pl_libplot_warning_handler)(const char *) = NULL;
37 int (*pl_libplot_error_handler)(const char *) = NULL;
38 #else /* LIBPLOTTER */
39 int (*pl_libplotter_warning_handler)(const char *) = NULL;
40 int (*pl_libplotter_error_handler)(const char *) = NULL;
41 #endif /* LIBPLOTTER */
42
43 /* The following variables (_plotters, _plotters_len) are global variables
44 in libplot, but static data members of the Plotter class in libplotter.
45 That's arranged by #ifdefs's in extern.h. */
46
47 /* Sparse array of pointers to Plotter instances, and its size.
48 Initialized to a NULL pointer, and 0, respectively.
49
50 Accessed by _g_initialize() and _g_terminate() in this file, and by
51 g_flush() in g_flushpl.c. */
52
53 Plotter **_plotters = NULL;
54 int _plotters_len = 0;
55
56 /* initial size for _plotters[], the sparse array of pointers to Plotter
57 instances */
58 #define INITIAL_PLOTTERS_LEN 4
59
60 /* Mutex for locking _plotters[] and _plotters_len. A global variable in
61 both libplot and libplotter. */
62 #ifdef PTHREAD_SUPPORT
63 #ifdef HAVE_PTHREAD_H
64 pthread_mutex_t _plotters_mutex = PTHREAD_MUTEX_INITIALIZER;
65 #endif
66 #endif
67
68 /* Pointer to distinguished (global) PlotterParams object, used by the old
69 (non-thread-safe) bindings. In libplotter, this is a static data member
70 of the Plotter class. That's arranged by an #ifdef in extern.h. */
71 PlotterParams *_old_api_global_plotter_params = NULL;
72
73 #ifndef LIBPLOTTER
74 /* In libplot, this is the initialization for the function-pointer part of
75 a Plotter struct. */
76 const Plotter _pl_g_default_plotter =
77 {
78 /* initialization (after creation) and termination (before deletion) */
79 _pl_g_initialize, _pl_g_terminate,
80 /* page manipulation */
81 _pl_g_begin_page, _pl_g_erase_page, _pl_g_end_page,
82 /* drawing state manipulation */
83 _pl_g_push_state, _pl_g_pop_state,
84 /* internal path-painting methods (endpath() is a wrapper for the first) */
85 _pl_g_paint_path, _pl_g_paint_paths, _pl_g_path_is_flushable, _pl_g_maybe_prepaint_segments,
86 /* internal methods for drawing of markers and points */
87 _pl_g_paint_marker, _pl_g_paint_point,
88 /* internal methods that plot strings in Hershey, non-Hershey fonts */
89 _pl_g_paint_text_string_with_escapes, _pl_g_paint_text_string,
90 _pl_g_get_text_width,
91 /* private low-level `retrieve font' method */
92 _pl_g_retrieve_font,
93 /* `flush output' method, called only if Plotter handles its own output */
94 _pl_g_flush_output,
95 /* error handlers */
96 _pl_g_warning,
97 _pl_g_error
98 };
99 #endif /* not LIBPLOTTER */
100
101 /* The private `initialize' method, invoked when a Plotter is created. It
102 does such things as initializing capability flags from the values of
103 class variables, allocating storage, etc. In the C binding, when this
104 is invoked _plotter points to the Plotter that has just been created.
105 In the C++ binding, this is a function member of the Plotter class, and
106 _plotter is an alias for `this'. */
107
108 void
_pl_g_initialize(S___ (Plotter * _plotter))109 _pl_g_initialize (S___(Plotter *_plotter))
110 {
111 bool open_slot = false;
112 int i, j;
113
114 #ifdef PTHREAD_SUPPORT
115 #ifdef HAVE_PTHREAD_H
116 /* lock the global variables _plotters[] and _plotters_len */
117 pthread_mutex_lock (&_plotters_mutex);
118 #endif
119 #endif
120
121 /* ensure plotter instance array is set up */
122 if (_plotters_len == 0)
123 {
124 _plotters = (Plotter **)_pl_xmalloc (INITIAL_PLOTTERS_LEN * sizeof(Plotter *));
125 for (i = 0; i < INITIAL_PLOTTERS_LEN; i++)
126 _plotters[i] = (Plotter *)NULL;
127 _plotters_len = INITIAL_PLOTTERS_LEN;
128 }
129
130 /* be sure there is an open slot (slot i) */
131 for (i = 0; i < _plotters_len; i++)
132 if (_plotters[i] == NULL)
133 {
134 open_slot = true;
135 break;
136 }
137
138 if (!open_slot)
139 /* expand array, clearing upper half */
140 {
141 i = _plotters_len;
142 _plotters =
143 (Plotter **)_pl_xrealloc (_plotters,
144 2 * _plotters_len * sizeof (Plotter *));
145 for (j = _plotters_len; j < 2 * _plotters_len; j++)
146 _plotters[j] = (Plotter *)NULL;
147 _plotters_len *= 2;
148 }
149
150 /* place just-created Plotter in open slot */
151 _plotters[i] = _plotter;
152
153 #ifdef PTHREAD_SUPPORT
154 #ifdef HAVE_PTHREAD_H
155 /* unlock the global variables _plotters[] and _plotters_len */
156 pthread_mutex_unlock (&_plotters_mutex);
157 #endif
158 #endif
159
160 /* Initialize all data members (except in/out/err streams and device
161 driver parameters). */
162
163 #ifndef LIBPLOTTER
164 /* tag field, will differ in derived classes */
165 _plotter->data->type = PL_GENERIC;
166 #endif
167
168 /* output model */
169 _plotter->data->output_model = PL_OUTPUT_NONE;
170
171 /* I/O, will not differ in derived classes */
172 _plotter->data->page = (plOutbuf *)NULL;
173 _plotter->data->first_page = (plOutbuf *)NULL;
174
175 /* basic data members, will not differ in derived classes */
176 _plotter->data->open = false;
177 _plotter->data->opened = false;
178 _plotter->data->page_number = 0;
179 _plotter->data->fontsize_invoked = false;
180 _plotter->data->linewidth_invoked = false;
181 _plotter->data->frame_number = 0;
182
183 /* drawing state stack (initially empty; same in derived classes) */
184 _plotter->drawstate = (plDrawState *)NULL;
185
186 /* warnings, will not differ in derived classes */
187 _plotter->data->font_warning_issued = false;
188 _plotter->data->pen_color_warning_issued = false;
189 _plotter->data->fill_color_warning_issued = false;
190 _plotter->data->bg_color_warning_issued = false;
191
192 /* user-queryable capabilities: 0/1/2 = no/yes/maybe */
193 _plotter->data->have_wide_lines = 1;
194 _plotter->data->have_dash_array = 1;
195 _plotter->data->have_odd_winding_fill = 1;
196 _plotter->data->have_nonzero_winding_fill = 1;
197 _plotter->data->have_settable_bg = 1;
198 _plotter->data->have_escaped_string_support = 1;
199 _plotter->data->have_ps_fonts = 1;
200 _plotter->data->have_pcl_fonts = 1;
201 _plotter->data->have_stick_fonts = 1;
202 _plotter->data->have_extra_stick_fonts = 0; /* specific to HP-GL version "1.5" */
203 _plotter->data->have_other_fonts = 0;
204
205 /* text and font-related parameters (internal, not queryable by user) */
206 _plotter->data->default_font_type = PL_F_HERSHEY;
207 _plotter->data->pcl_before_ps = false;
208 _plotter->data->have_horizontal_justification = false;
209 _plotter->data->have_vertical_justification = false;
210 _plotter->data->kern_stick_fonts = false;
211 _plotter->data->issue_font_warning = true;
212
213 /* path-related parameters (also internal) */
214 _plotter->data->max_unfilled_path_length = PL_MAX_UNFILLED_PATH_LENGTH;
215 _plotter->data->have_mixed_paths = false;
216 _plotter->data->allowed_arc_scaling = AS_NONE;
217 _plotter->data->allowed_ellarc_scaling = AS_NONE;
218 _plotter->data->allowed_quad_scaling = AS_NONE;
219 _plotter->data->allowed_cubic_scaling = AS_NONE;
220 _plotter->data->allowed_box_scaling = AS_NONE;
221 _plotter->data->allowed_circle_scaling = AS_NONE;
222 _plotter->data->allowed_ellipse_scaling = AS_NONE;
223
224 /* color-related parameters (also internal) */
225 _plotter->data->emulate_color = false;
226
227 /* dimensions */
228 _plotter->data->display_model_type = (int)DISP_MODEL_VIRTUAL;
229 _plotter->data->display_coors_type = (int)DISP_DEVICE_COORS_REAL;
230 _plotter->data->flipped_y = false;
231 _plotter->data->imin = 0;
232 _plotter->data->imax = 0;
233 _plotter->data->jmin = 0;
234 _plotter->data->jmax = 0;
235 _plotter->data->xmin = 0.0;
236 _plotter->data->xmax = 1.0;
237 _plotter->data->ymin = 0.0;
238 _plotter->data->ymax = 1.0;
239 _plotter->data->page_data = (plPageData *)NULL;
240
241 /* compute the NDC to device-frame affine map, set it in Plotter */
242 _compute_ndc_to_device_map (_plotter->data);
243
244 /* create, initialize cache of color name -> RGB correspondences */
245 _plotter->data->color_name_cache = _create_color_name_cache ();
246
247 /* initialize certain data members from values of relevant device
248 driver parameters */
249
250 /* emulate color by using grayscale? */
251 {
252 const char *emulate_s;
253
254 emulate_s = (const char *)_get_plot_param (_plotter->data,
255 "EMULATE_COLOR");
256 if (strcmp (emulate_s, "yes") == 0)
257 _plotter->data->emulate_color = true;
258 else
259 _plotter->data->emulate_color = false;
260 }
261
262 /* set maximum polyline length (relevant to most Plotters, esp. those
263 that do not do real time output) */
264 {
265 const char *length_s;
266 int local_length;
267
268 length_s = (const char *)_get_plot_param (_plotter->data,
269 "MAX_LINE_LENGTH");
270
271 if (sscanf (length_s, "%d", &local_length) <= 0 || local_length <= 0)
272 {
273 length_s = (const char *)_get_default_plot_param ("MAX_LINE_LENGTH");
274 sscanf (length_s, "%d", &local_length);
275 }
276 _plotter->data->max_unfilled_path_length = local_length;
277 }
278
279 /* Ensure widths of labels rendered in the Stick fonts are correctly
280 computed. This is a kludge (in pre-HP-GL/2, Stick fonts were kerned;
281 see g_alabel.c.) */
282 {
283 const char *version_s;
284
285 version_s = (const char *)_get_plot_param (_plotter->data,
286 "HPGL_VERSION");
287 if (strcmp (version_s, "2") == 0) /* modern HP-GL/2 (default) */
288 _plotter->data->kern_stick_fonts = false;
289 else if (strcmp (version_s, "1.5") == 0) /* HP7550A */
290 _plotter->data->kern_stick_fonts = true;
291 else if (strcmp (version_s, "1") == 0) /* generic HP-GL */
292 _plotter->data->kern_stick_fonts = true; /* meaningless (no stick fonts) */
293 }
294
295 #ifdef MSDOS
296 /* A DJGPP enhancement (thanks, Michel de Ruiter). If the output fp is
297 standard output, and standard output has been redirected to a file,
298 then set the output mode to binary. This turns off character mapping,
299 which is a necessity when writing binary output formats such as GIF or
300 Tektronix. If the output fp is a (FILE *) other than standard output,
301 then whoever opened it is responsible for having opened it with mode
302 "wb" instead of "wt" or "w". */
303 if (_plotter->data->outfp
304 && (_plotter->data->outfp == stdout)
305 && O_BINARY
306 && !isatty (fileno (stdout)))
307 {
308 fflush (stdout);
309 setmode (fileno (stdout), O_BINARY);
310 }
311 #endif
312 }
313
314 /* The private `terminate' method, which is invoked when a Plotter is
315 deleted, provided that it is non-NULL. It may do such things as write
316 to an output stream from internal storage, deallocate storage, etc. */
317
318 void
_pl_g_terminate(S___ (Plotter * _plotter))319 _pl_g_terminate (S___(Plotter *_plotter))
320 {
321 int i;
322
323 /* if specified plotter is open, close it */
324 if (_plotter->data->open)
325 _API_closepl (S___(_plotter));
326
327 /* free instance-specific copies of class parameters */
328 _pl_g_free_params_in_plotter (S___(_plotter));
329
330 /* free color name cache */
331 _delete_color_name_cache (_plotter->data->color_name_cache);
332
333 /* remove Plotter from sparse Plotter array */
334
335 #ifdef PTHREAD_SUPPORT
336 #ifdef HAVE_PTHREAD_H
337 /* lock the global variables _plotters[] and _plotters_len */
338 pthread_mutex_lock (&_plotters_mutex);
339 #endif
340 #endif
341 for (i = 0; i < _plotters_len; i++)
342 if (_plotters[i] == _plotter)
343 {
344 _plotters[i] = (Plotter *)NULL;
345 break;
346 }
347 #ifdef PTHREAD_SUPPORT
348 #ifdef HAVE_PTHREAD_H
349 /* unlock the global variables _plotters[] and _plotters_len */
350 pthread_mutex_unlock (&_plotters_mutex);
351 #endif
352 #endif
353 }
354
355 #ifdef LIBPLOTTER
356
357 /* OLD API; not thread-safe (these ctors take values for Plotter
358 parameters from the global PlotterParams struct) */
359
Plotter(FILE * infile,FILE * outfile,FILE * errfile)360 Plotter::Plotter (FILE *infile, FILE *outfile, FILE *errfile)
361 {
362 /* create PlotterData structure, install it in Plotter */
363 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
364
365 _plotter->data->infp = infile;
366 _plotter->data->outfp = outfile;
367 _plotter->data->errfp = errfile;
368 _plotter->data->instream = NULL;
369 _plotter->data->outstream = NULL;
370 _plotter->data->errstream = NULL;
371 /* copy in the current values of device driver parameters */
372 if (_old_api_global_plotter_params == NULL)
373 _old_api_global_plotter_params = new PlotterParams;
374 _pl_g_copy_params_to_plotter (_old_api_global_plotter_params);
375
376 _pl_g_initialize ();
377 }
378
Plotter(FILE * outfile)379 Plotter::Plotter (FILE *outfile)
380 {
381 /* create PlotterData structure, install it in Plotter */
382 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
383
384 _plotter->data->infp = NULL;
385 _plotter->data->outfp = outfile;
386 _plotter->data->errfp = NULL;
387 _plotter->data->instream = NULL;
388 _plotter->data->outstream = NULL;
389 _plotter->data->errstream = NULL;
390 /* copy in the current values of device driver parameters */
391 if (_old_api_global_plotter_params == NULL)
392 _old_api_global_plotter_params = new PlotterParams;
393 _pl_g_copy_params_to_plotter (_old_api_global_plotter_params);
394
395 _pl_g_initialize ();
396 }
397
Plotter(istream & in,ostream & out,ostream & err)398 Plotter::Plotter (istream& in, ostream& out, ostream& err)
399 {
400 /* create PlotterData structure, install it in Plotter */
401 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
402
403 _plotter->data->infp = NULL;
404 _plotter->data->outfp = NULL;
405 _plotter->data->errfp = NULL;
406 if (in.rdbuf())
407 _plotter->data->instream = ∈
408 else
409 _plotter->data->instream = NULL;
410 if (out.rdbuf())
411 _plotter->data->outstream = &out;
412 else
413 _plotter->data->outstream = NULL;
414 if (err.rdbuf())
415 _plotter->data->errstream = &err;
416 else
417 _plotter->data->errstream = NULL;
418 /* copy in the current values of device driver parameters */
419 if (_old_api_global_plotter_params == NULL)
420 _old_api_global_plotter_params = new PlotterParams;
421 _pl_g_copy_params_to_plotter (_old_api_global_plotter_params);
422
423 _pl_g_initialize ();
424 }
425
Plotter(ostream & out)426 Plotter::Plotter (ostream& out)
427 {
428 /* create PlotterData structure, install it in Plotter */
429 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
430
431 _plotter->data->infp = NULL;
432 _plotter->data->outfp = NULL;
433 _plotter->data->errfp = NULL;
434 _plotter->data->instream = NULL;
435 if (out.rdbuf())
436 _plotter->data->outstream = &out;
437 else
438 _plotter->data->outstream = NULL;
439 _plotter->data->errstream = NULL;
440 /* copy in the current values of device driver parameters */
441 if (_old_api_global_plotter_params == NULL)
442 _old_api_global_plotter_params = new PlotterParams;
443 _pl_g_copy_params_to_plotter (_old_api_global_plotter_params);
444
445 _pl_g_initialize ();
446 }
447
Plotter()448 Plotter::Plotter ()
449 {
450 /* create PlotterData structure, install it in Plotter */
451 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
452
453 _plotter->data->infp = NULL;
454 _plotter->data->outfp = NULL;
455 _plotter->data->errfp = NULL;
456 _plotter->data->instream = NULL;
457 _plotter->data->outstream = NULL;
458 _plotter->data->errstream = NULL;
459 /* copy in the current values of device driver parameters */
460 if (_old_api_global_plotter_params == NULL)
461 _old_api_global_plotter_params = new PlotterParams;
462 _pl_g_copy_params_to_plotter (_old_api_global_plotter_params);
463
464 _pl_g_initialize ();
465 }
466
467 /* NEW API; thread-safe (since user can specify a local PlotterParams
468 struct from which parameters should be taken) */
469
Plotter(FILE * infile,FILE * outfile,FILE * errfile,PlotterParams & plotter_params)470 Plotter::Plotter (FILE *infile, FILE *outfile, FILE *errfile, PlotterParams &plotter_params)
471 {
472 /* create PlotterData structure, install it in Plotter */
473 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
474
475 _plotter->data->infp = infile;
476 _plotter->data->outfp = outfile;
477 _plotter->data->errfp = errfile;
478 _plotter->data->instream = NULL;
479 _plotter->data->outstream = NULL;
480 _plotter->data->errstream = NULL;
481 /* copy in the specified values of device driver parameters */
482 _pl_g_copy_params_to_plotter (&plotter_params);
483
484 _pl_g_initialize ();
485 }
486
Plotter(FILE * outfile,PlotterParams & plotter_params)487 Plotter::Plotter (FILE *outfile, PlotterParams &plotter_params)
488 {
489 /* create PlotterData structure, install it in Plotter */
490 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
491
492 _plotter->data->infp = NULL;
493 _plotter->data->outfp = outfile;
494 _plotter->data->errfp = NULL;
495 _plotter->data->instream = NULL;
496 _plotter->data->outstream = NULL;
497 _plotter->data->errstream = NULL;
498 /* copy in the specified values of device driver parameters */
499 _pl_g_copy_params_to_plotter (&plotter_params);
500
501 _pl_g_initialize ();
502 }
503
Plotter(istream & in,ostream & out,ostream & err,PlotterParams & plotter_params)504 Plotter::Plotter (istream& in, ostream& out, ostream& err, PlotterParams &plotter_params)
505 {
506 /* create PlotterData structure, install it in Plotter */
507 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
508
509 _plotter->data->infp = NULL;
510 _plotter->data->outfp = NULL;
511 _plotter->data->errfp = NULL;
512 if (in.rdbuf())
513 _plotter->data->instream = ∈
514 else
515 _plotter->data->instream = NULL;
516 if (out.rdbuf())
517 _plotter->data->outstream = &out;
518 else
519 _plotter->data->outstream = NULL;
520 if (err.rdbuf())
521 _plotter->data->errstream = &err;
522 else
523 _plotter->data->errstream = NULL;
524 /* copy in the specified values of device driver parameters */
525 _pl_g_copy_params_to_plotter (&plotter_params);
526
527 _pl_g_initialize ();
528 }
529
Plotter(ostream & out,PlotterParams & plotter_params)530 Plotter::Plotter (ostream& out, PlotterParams &plotter_params)
531 {
532 /* create PlotterData structure, install it in Plotter */
533 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
534
535 _plotter->data->infp = NULL;
536 _plotter->data->outfp = NULL;
537 _plotter->data->errfp = NULL;
538 _plotter->data->instream = NULL;
539 if (out.rdbuf())
540 _plotter->data->outstream = &out;
541 else
542 _plotter->data->outstream = NULL;
543 _plotter->data->errstream = NULL;
544 /* copy in the specified values of device driver parameters */
545 _pl_g_copy_params_to_plotter (&plotter_params);
546
547 _pl_g_initialize ();
548 }
549
Plotter(PlotterParams & plotter_params)550 Plotter::Plotter (PlotterParams &plotter_params)
551 {
552 /* create PlotterData structure, install it in Plotter */
553 _plotter->data = (plPlotterData *)_pl_xmalloc (sizeof(plPlotterData));
554
555 _plotter->data->infp = NULL;
556 _plotter->data->outfp = NULL;
557 _plotter->data->errfp = NULL;
558 _plotter->data->instream = NULL;
559 _plotter->data->outstream = NULL;
560 _plotter->data->errstream = NULL;
561 /* copy in the specified values of device driver parameters */
562 _pl_g_copy_params_to_plotter (&plotter_params);
563
564 _pl_g_initialize ();
565 }
566
~Plotter()567 Plotter::~Plotter ()
568 {
569 _pl_g_terminate ();
570
571 /* destroy PlotterData structure in Plotter */
572 free (_plotter->data);
573 }
574 #endif
575