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 = &in;
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 = &in;
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