PLplot  5.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plcore.c
Go to the documentation of this file.
1 // Central dispatch facility for PLplot.
2 // Also contains the PLplot main data structures, external access
3 // routines, and initialization calls.
4 //
5 // This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
6 //
7 //
8 // Copyright (C) 2004 Joao Cardoso
9 // Copyright (C) 2004, 2005 Rafael Laboissiere
10 // Copyright (C) 2004, 2006 Andrew Ross
11 // Copyright (C) 2004 Andrew Roach
12 // Copyright (C) 2005-2015 Alan W. Irwin
13 // Copyright (C) 2005 Thomas J. Duck
14 //
15 // This file is part of PLplot.
16 //
17 // PLplot is free software; you can redistribute it and/or modify
18 // it under the terms of the GNU Library General Public License as published
19 // by the Free Software Foundation; either version 2 of the License, or
20 // (at your option) any later version.
21 //
22 // PLplot is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU Library General Public License for more details.
26 //
27 // You should have received a copy of the GNU Library General Public License
28 // along with PLplot; if not, write to the Free Software
29 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 //
31 //
32 
33 #define DEBUG
34 #define NEED_PLDEBUG
35 #include "plcore.h"
36 
37 #ifdef ENABLE_DYNDRIVERS
38  #ifndef LTDL_WIN32
39  #include <ltdl.h>
40  #else
41  #include "ltdl_win32.h"
42  #endif
43 #endif
44 
45 #if HAVE_DIRENT_H
46 // The following conditional is a workaround for a bug in the MacOSX system.
47 // When the dirent.h file will be fixed upstream by Apple Inc, this should
48 // go away.
49 # ifdef NEED_SYS_TYPE_H
50 # include <sys/types.h>
51 # endif
52 # include <dirent.h>
53 # define NAMLEN( dirent ) strlen( ( dirent )->d_name )
54 #else
55 # if defined ( _MSC_VER )
56 # include "dirent_msvc.h"
57 # else
58 # define dirent direct
59 # define NAMLEN( dirent ) ( dirent )->d_namlen
60 # if HAVE_SYS_NDIR_H
61 # include <sys/ndir.h>
62 # endif
63 # if HAVE_SYS_DIR_H
64 # include <sys/dir.h>
65 # endif
66 # if HAVE_NDIR_H
67 # include <ndir.h>
68 # endif
69 # endif
70 #endif
71 
72 // AM: getcwd has a somewhat strange status on Windows, its proper
73 // name is _getcwd, this is a problem in the case of DLLs, like with
74 // the Java bindings. The functions _getcwd() and chdir() are
75 // declared in direct.h for Visual C++. Since chdir() is deprecated
76 // (but still available) in Visual C++ we redefine chdir to _chdir.
77 //
78 #if defined ( _MSC_VER )
79 # include <direct.h>
80 # define getcwd _getcwd
81 # define chdir _chdir
82 #endif
83 
84 #define BUFFER_SIZE 80
85 #define BUFFER2_SIZE 300
86 #define DRVSPEC_SIZE 400
87 
88 #include <errno.h>
89 
90 int
91 text2num( const char *text, char end, PLUNICODE *num );
92 
93 int
94 text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower );
95 
96 //--------------------------------------------------------------------------
97 // Driver Interface
98 //
99 // These routines are the low-level interface to the driver -- all calls to
100 // driver functions must pass through here. For implementing driver-
101 // specific functions, the escape function is provided. The command stream
102 // gets duplicated to the plot buffer here.
103 //
104 // All functions that result in graphics actually being plotted (rather than
105 // just a change of state) are filtered as necessary before being passed on.
106 // The default settings do not require any filtering, i.e. PLplot physical
107 // coordinates are the same as the device physical coordinates (currently
108 // this can't be changed anyway), and a global view equal to the entire page
109 // is used.
110 //
111 // The reason one wants to put view-specific filtering here is that if
112 // enabled, the plot buffer should receive the unfiltered data stream. This
113 // allows a specific view to be used from an interactive device (e.g. TCL/TK
114 // driver) but be restored to the full view at any time merely by
115 // reprocessing the contents of the plot buffer.
116 //
117 // The metafile, on the other hand, *should* be affected by changes in the
118 // view, since this is a crucial editing capability. It is recommended that
119 // the initial metafile be created without a restricted global view, and
120 // modification of the view done on a per-plot basis as desired during
121 // subsequent processing.
122 //
123 //--------------------------------------------------------------------------
124 
125 enum { AT_BOP, DRAWING, AT_EOP };
126 
127 // Initialize device.
128 // The plot buffer must be called last.
129 
130 // The following array of chars is used both here and in plsym.c for
131 // translating the Greek characters from the #g escape sequences into
132 // the Hershey and Unicode codings
133 //
134 const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
135 
136 void
137 plP_init( void )
138 {
139  char * save_locale;
140  plsc->page_status = AT_EOP;
141  plsc->stream_closed = FALSE;
142 
143  save_locale = plsave_set_locale();
144  ( *plsc->dispatch_table->pl_init )( (struct PLStream_struct *) plsc );
145  plrestore_locale( save_locale );
146 
147  if ( plsc->plbuf_write )
148  plbuf_init( plsc );
149 }
150 
151 // End of page
152 // The plot buffer must be called first.
153 // Ignore instruction if already at eop.
154 
155 void
156 plP_eop( void )
157 {
158  int skip_driver_eop = 0;
159 
160  if ( plsc->page_status == AT_EOP )
161  return;
162 
163  plsc->page_status = AT_EOP;
164 
165  if ( plsc->plbuf_write )
166  plbuf_eop( plsc );
167 
168 // Call user eop handler if present.
169 
170  if ( plsc->eop_handler != NULL )
171  ( *plsc->eop_handler )( plsc->eop_data, &skip_driver_eop );
172 
173  if ( !skip_driver_eop )
174  {
175  char *save_locale = plsave_set_locale();
176  if ( !plsc->stream_closed )
177  {
178  ( *plsc->dispatch_table->pl_eop )( (struct PLStream_struct *) plsc );
179  }
180  plrestore_locale( save_locale );
181  }
182 }
183 
184 // Set up new page.
185 // The plot buffer must be called last.
186 // Ignore if already at bop.
187 // It's not actually necessary to be AT_EOP here, so don't check for it.
188 
189 void
190 plP_bop( void )
191 {
192  int skip_driver_bop = 0;
193 
194  plP_subpInit();
195  if ( plsc->page_status == AT_BOP )
196  return;
197 
198  plsc->page_status = AT_BOP;
199  plsc->nplwin = 0;
200 
201 // Call user bop handler if present.
202 
203  if ( plsc->bop_handler != NULL )
204  ( *plsc->bop_handler )( plsc->bop_data, &skip_driver_bop );
205 
206  if ( !skip_driver_bop )
207  {
208  char *save_locale = plsave_set_locale();
209  if ( !plsc->stream_closed )
210  {
211  ( *plsc->dispatch_table->pl_bop )( (struct PLStream_struct *) plsc );
212  }
213  plrestore_locale( save_locale );
214  }
215 
216  if ( plsc->plbuf_write )
217  plbuf_bop( plsc );
218 }
219 
220 // Tidy up device (flush buffers, close file, etc).
221 
222 void
223 plP_tidy( void )
224 {
225  char * save_locale;
226  if ( plsc->tidy )
227  {
228  ( *plsc->tidy )( plsc->tidy_data );
229  plsc->tidy = NULL;
230  plsc->tidy_data = NULL;
231  }
232 
233  save_locale = plsave_set_locale();
234  if ( !plsc->stream_closed )
235  {
236  ( *plsc->dispatch_table->pl_tidy )( (struct PLStream_struct *) plsc );
237  }
238  plrestore_locale( save_locale );
239 
240  if ( plsc->plbuf_write )
241  {
242  plbuf_tidy( plsc );
243  }
244 
245  plsc->OutFile = NULL;
246 }
247 
248 // Change state.
249 
250 void
252 {
253  char * save_locale;
254  if ( plsc->plbuf_write )
255  plbuf_state( plsc, op );
256 
257  save_locale = plsave_set_locale();
258  if ( !plsc->stream_closed )
259  {
260  ( *plsc->dispatch_table->pl_state )( (struct PLStream_struct *) plsc, op );
261  }
262  plrestore_locale( save_locale );
263 }
264 
265 // Escape function, for driver-specific commands.
266 
267 void
268 plP_esc( PLINT op, void *ptr )
269 {
270  char * save_locale;
271  PLINT clpxmi, clpxma, clpymi, clpyma;
272  EscText* args;
273 
274  // The plot buffer must be called first
275  if ( plsc->plbuf_write )
276  plbuf_esc( plsc, op, ptr );
277 
278  // Text coordinates must pass through the driver interface filter
279  if ( ( op == PLESC_HAS_TEXT && plsc->dev_unicode ) ||
280  ( op == PLESC_END_TEXT && plsc->alt_unicode ) )
281  {
282  // Apply the driver interface filter
283  if ( plsc->difilt )
284  {
285  args = (EscText *) ptr;
286  difilt( &( args->x ), &( args->y ), 1, &clpxmi, &clpxma, &clpymi, &clpyma );
287  }
288  }
289 
290  save_locale = plsave_set_locale();
291  if ( !plsc->stream_closed )
292  {
293  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, op, ptr );
294  }
295  plrestore_locale( save_locale );
296 }
297 
298 // Set up plot window parameters.
299 // The plot buffer must be called first
300 // Some drivers (metafile, Tk) need access to this data
301 
302 void
304 {
305  PLWindow *w;
306  PLINT clpxmi, clpxma, clpymi, clpyma;
307 
308 // Provide plot buffer with unfiltered window data
309 
310  if ( plsc->plbuf_write )
311  plbuf_esc( plsc, PLESC_SWIN, (void *) plwin );
312 
313  w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
314 
315  w->dxmi = plwin->dxmi;
316  w->dxma = plwin->dxma;
317  w->dymi = plwin->dymi;
318  w->dyma = plwin->dyma;
319 
320  if ( plsc->difilt )
321  {
322  xscl[0] = plP_dcpcx( w->dxmi );
323  xscl[1] = plP_dcpcx( w->dxma );
324  yscl[0] = plP_dcpcy( w->dymi );
325  yscl[1] = plP_dcpcy( w->dyma );
326 
327  difilt( xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma );
328 
329  w->dxmi = plP_pcdcx( xscl[0] );
330  w->dxma = plP_pcdcx( xscl[1] );
331  w->dymi = plP_pcdcy( yscl[0] );
332  w->dyma = plP_pcdcy( yscl[1] );
333  }
334 
335  w->wxmi = plwin->wxmi;
336  w->wxma = plwin->wxma;
337  w->wymi = plwin->wymi;
338  w->wyma = plwin->wyma;
339 
340 // If the driver wants to process swin commands, call it now
341 // It must use the filtered data, which it can get from *plsc
342 
343  if ( plsc->dev_swin )
344  {
345  char *save_locale = plsave_set_locale();
346  if ( !plsc->stream_closed )
347  {
348  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
349  PLESC_SWIN, NULL );
350  }
351  plrestore_locale( save_locale );
352  }
353 }
354 
355 //--------------------------------------------------------------------------
356 // Drawing commands.
357 //--------------------------------------------------------------------------
358 
359 // Draw line between two points
360 // The plot buffer must be called first so it gets the unfiltered data
361 
362 void
363 plP_line( short *x, short *y )
364 {
365  PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
366 
367  plsc->page_status = DRAWING;
368 
369  if ( plsc->plbuf_write )
370  plbuf_line( plsc, x[0], y[0], x[1], y[1] );
371 
372  if ( plsc->difilt )
373  {
374  for ( i = 0; i < npts; i++ )
375  {
376  xscl[i] = x[i];
377  yscl[i] = y[i];
378  }
379  difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
380  plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline );
381  }
382  else
383  {
384  grline( x, y, npts );
385  }
386 }
387 
388 // Draw polyline
389 // The plot buffer must be called first
390 
391 void
392 plP_polyline( short *x, short *y, PLINT npts )
393 {
394  PLINT i, clpxmi, clpxma, clpymi, clpyma;
395 
396  plsc->page_status = DRAWING;
397 
398  if ( plsc->plbuf_write )
399  plbuf_polyline( plsc, x, y, npts );
400 
401  if ( plsc->difilt )
402  {
403  for ( i = 0; i < npts; i++ )
404  {
405  xscl[i] = x[i];
406  yscl[i] = y[i];
407  }
408  difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
409  plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
410  grpolyline );
411  }
412  else
413  {
414  grpolyline( x, y, npts );
415  }
416 }
417 
418 // Fill polygon
419 // The plot buffer must be called first
420 // Here if the desired area fill capability isn't present, we mock up
421 // something in software
422 
423 static int foo;
424 
425 void
426 plP_fill( short *x, short *y, PLINT npts )
427 {
428  PLINT i, clpxmi, clpxma, clpymi, clpyma;
429 
430  plsc->page_status = DRAWING;
431 
432  if ( plsc->plbuf_write )
433  {
434  plsc->dev_npts = npts;
435  plsc->dev_x = x;
436  plsc->dev_y = y;
437  plbuf_esc( plsc, PLESC_FILL, NULL );
438  }
439 
440 // Account for driver ability to do fills
441 
442  if ( plsc->patt == 0 && !plsc->dev_fill0 )
443  {
444  if ( !foo )
445  {
446  plwarn( "Driver does not support hardware solid fills, switching to software fill.\n" );
447  foo = 1;
448  }
449  plsc->patt = 8;
450  plpsty( plsc->patt );
451  }
452  if ( plsc->dev_fill1 )
453  {
454  plsc->patt = -ABS( plsc->patt );
455  }
456 
457 // Perform fill. Here we MUST NOT allow the software fill to pass through the
458 // driver interface filtering twice, else we get the infamous 2*rotation for
459 // software fills on orientation swaps.
460 //
461 
462  if ( plsc->patt > 0 )
463  plfill_soft( x, y, npts );
464 
465  else
466  {
467  if ( plsc->difilt )
468  {
469  for ( i = 0; i < npts; i++ )
470  {
471  xscl[i] = x[i];
472  yscl[i] = y[i];
473  }
474  difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
475  plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
476  grfill );
477  }
478  else
479  {
480  grfill( x, y, npts );
481  }
482  }
483 }
484 
485 // Render a gradient
486 // The plot buffer must be called first
487 // N.B. plP_gradient is never called (see plgradient) unless the
488 // device driver has set plsc->dev_gradient to true.
489 
490 void
491 plP_gradient( short *x, short *y, PLINT npts )
492 {
493  PLINT i, clpxmi, clpxma, clpymi, clpyma;
494 
495  plsc->page_status = DRAWING;
496 
497  if ( plsc->plbuf_write )
498  {
499  plsc->dev_npts = npts;
500  plsc->dev_x = x;
501  plsc->dev_y = y;
502  plbuf_esc( plsc, PLESC_GRADIENT, NULL );
503  }
504 
505  // Render gradient with driver.
506  if ( plsc->difilt )
507  {
508  for ( i = 0; i < npts; i++ )
509  {
510  xscl[i] = x[i];
511  yscl[i] = y[i];
512  }
513  difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
514  plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
515  grgradient );
516  }
517  else
518  {
519  grgradient( x, y, npts );
520  }
521 }
522 
523 // Account for driver ability to draw text itself
524 //
525 // #define DEBUG_TEXT
526 //
527 
528 //--------------------------------------------------------------------------
529 // int text2num( char *text, char end, PLUNICODE *num)
530 // char *text - pointer to the text to be parsed
531 // char end - end character (i.e. ')' or ']' to stop parsing
532 // PLUNICODE *num - pointer to an PLUNICODE to store the value
533 //
534 // Function takes a string, which can be either hex or decimal,
535 // and converts it into an PLUNICODE, stopping at either a null,
536 // or the character pointed to by 'end'. This implementation using
537 // the C library strtoul replaces the original brain-dead version
538 // and should be more robust to invalid control strings.
539 //--------------------------------------------------------------------------
540 
541 int text2num( const char *text, char end, PLUNICODE *num )
542 {
543  char *endptr;
544  char msgbuf[BUFFER_SIZE];
545 
546  *num = (PLUNICODE) strtoul( text, &endptr, 0 );
547 
548  if ( end != endptr[0] )
549  {
550  snprintf( msgbuf, BUFFER_SIZE, "text2num: invalid control string detected - %c expected", end );
551  plwarn( msgbuf );
552  }
553 
554  return (int) ( endptr - text );
555 }
556 
557 //--------------------------------------------------------------------------
558 // int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
559 // char *text - pointer to the text to be parsed
560 // unsigned char *hexdigit - pointer to hex value that is stored.
561 // unsigned char *hexpower - pointer to hex power (left shift) that is stored.
562 //
563 // Function takes a pointer to a string, which is looked up in a table
564 // to determine the corresponding FCI (font characterization integer)
565 // hex digit value and hex power (left shift). All matched strings
566 // start with "<" and end with the two characters "/>".
567 // If the lookup succeeds, hexdigit and hexpower are set to the appropriate
568 // values in the table, and the function returns the number of characters
569 // in text that are consumed by the matching string in the table lookup.
570 //
571 // If the lookup fails, hexdigit is set to 0, hexpower is set to and
572 // impossible value, and the function returns 0.
573 //--------------------------------------------------------------------------
574 
575 int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower )
576 {
577  typedef struct
578  {
579  const char *ptext;
580  unsigned char hexdigit;
581  unsigned char hexpower;
582  }
583  TextLookupTable;
584  // This defines the various font control commands and the corresponding
585  // hexdigit and hexpower in the FCI.
586  //
587 #define N_TextLookupTable 10
588  const TextLookupTable lookup[N_TextLookupTable] = {
589  { "<sans-serif/>", PL_FCI_SANS, PL_FCI_FAMILY },
590  { "<serif/>", PL_FCI_SERIF, PL_FCI_FAMILY },
591  { "<monospace/>", PL_FCI_MONO, PL_FCI_FAMILY },
592  { "<script/>", PL_FCI_SCRIPT, PL_FCI_FAMILY },
593  { "<symbol/>", PL_FCI_SYMBOL, PL_FCI_FAMILY },
594  { "<upright/>", PL_FCI_UPRIGHT, PL_FCI_STYLE },
595  { "<italic/>", PL_FCI_ITALIC, PL_FCI_STYLE },
596  { "<oblique/>", PL_FCI_OBLIQUE, PL_FCI_STYLE },
597  { "<medium/>", PL_FCI_MEDIUM, PL_FCI_WEIGHT },
598  { "<bold/>", PL_FCI_BOLD, PL_FCI_WEIGHT }
599  };
600  int i, length;
601  for ( i = 0; i < N_TextLookupTable; i++ )
602  {
603  length = (int) strlen( lookup[i].ptext );
604  if ( !strncmp( text, lookup[i].ptext, (size_t) length ) )
605  {
606  *hexdigit = lookup[i].hexdigit;
607  *hexpower = lookup[i].hexpower;
608  return ( length );
609  }
610  }
611  *hexdigit = 0;
612  *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
613  return ( 0 );
614 }
615 
616 static
617 void alternate_unicode_processing( const char * string, EscText * args )
618 {
619  size_t i, len;
620  char esc;
621  unsigned char hexdigit, hexpower;
622  PLUNICODE fci;
623  PLUNICODE orig_fci;
624  PLINT ig;
625  int skip;
626  PLUNICODE code;
627  int idx = -1;
628 
629  // Initialize to an empty string
630  args->unicode_array_len = 0;
631 
632  len = strlen( string );
633 
634  // If the string is empty, return now
635  if ( len == 0 )
636  return;
637 
638  // Get the current escape character
639  plgesc( &esc );
640 
641  // Obtain FCI (font characterization integer) for start of string.
642  plgfci( &fci );
643  orig_fci = fci;
644 
645  // Signal the begin of text processing to the driver
646  args->n_fci = fci;
647  plP_esc( PLESC_BEGIN_TEXT, args );
648 
649  for ( i = 0; i < len; i++ )
650  {
651  skip = 0;
652 
653  if ( string[i] == esc )
654  {
655  switch ( string[i + 1] )
656  {
657  case '(': // hershey code
658  i += 2 + text2num( &string[i + 2], ')', &code );
659  idx = plhershey2unicode( (int) code );
660  args->n_char =
662  plP_esc( PLESC_TEXT_CHAR, args );
663 
664  skip = 1;
665  break;
666 
667  case '[': // unicode
668  i += 2 + text2num( &string[i + 2], ']', &code );
669  args->n_char = code;
670  plP_esc( PLESC_TEXT_CHAR, args );
671  skip = 1;
672  break;
673 
674  case '<': // change font
675  if ( '0' <= string[i + 2] && string[i + 2] <= '9' )
676  {
677  i += 2 + text2num( &string[i + 2], '>', &code );
678  if ( code & PL_FCI_MARK )
679  {
680  // code is a complete FCI (font characterization
681  // integer): change FCI to this value.
682  //
683  fci = code;
684  skip = 1;
685 
686  args->n_fci = fci;
688  plP_esc( PLESC_CONTROL_CHAR, args );
689  }
690  else
691  {
692  // code is not complete FCI. Change
693  // FCI with hex power in rightmost hex
694  // digit and hex digit value in second rightmost
695  // hex digit.
696  //
697  hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK;
698  hexpower = code & PL_FCI_HEXPOWER_MASK;
699  plP_hex2fci( hexdigit, hexpower, &fci );
700  skip = 1;
701 
702  args->n_fci = fci;
704  plP_esc( PLESC_CONTROL_CHAR, args );
705  }
706  }
707  else
708  {
709  i += text2fci( &string[i + 1], &hexdigit, &hexpower );
710  if ( hexpower < 7 )
711  {
712  plP_hex2fci( hexdigit, hexpower, &fci );
713  skip = 1;
714 
715  args->n_fci = fci;
717  plP_esc( PLESC_CONTROL_CHAR, args );
718  }
719  }
720  break;
721 
722  case 'f': // Deprecated Hershey-style font change
723  case 'F': // Deprecated Hershey-style font change
724  // We implement an approximate response here so that
725  // reasonable results are obtained for unicode fonts,
726  // but this method is deprecated and the #<nnn> or
727  // #<command string> methods should be used instead
728  // to change unicode fonts in mid-string.
729  //
730  fci = PL_FCI_MARK;
731  if ( string[i + 2] == 'n' )
732  {
733  // medium, upright, sans-serif
735  }
736  else if ( string[i + 2] == 'r' )
737  {
738  // medium, upright, serif
740  }
741  else if ( string[i + 2] == 'i' )
742  {
743  // medium, italic, serif
746  }
747  else if ( string[i + 2] == 's' )
748  {
749  // medium, upright, script
751  }
752  else
753  fci = PL_FCI_IMPOSSIBLE;
754 
755  if ( fci != PL_FCI_IMPOSSIBLE )
756  {
757  i += 2;
758  skip = 1;
759 
760  args->n_fci = fci;
762  plP_esc( PLESC_CONTROL_CHAR, args );
763  }
764  break;
765 
766  case 'g': // Greek font
767  case 'G': // Greek font
768  // Get the index in the lookup table
769  // 527 = upper case alpha displacement in Hershey Table
770  // 627 = lower case alpha displacement in Hershey Table
771  //
772  ig = plP_strpos( plP_greek_mnemonic, string[i + 2] );
773  if ( ig >= 0 )
774  {
775  if ( ig >= 24 )
776  ig = ig + 100 - 24;
777  ig = ig + 527;
778  // Follow pldeco in plsym.c which for
779  // lower case epsilon, theta, and phi
780  // substitutes (684, 685, and 686) for
781  // (631, 634, and 647)
782  if ( ig == 631 )
783  ig = 684;
784  else if ( ig == 634 )
785  ig = 685;
786  else if ( ig == 647 )
787  ig = 686;
788  idx = plhershey2unicode( ig );
789  i += 2;
790  skip = 1; // skip is set if we have copied something
791  // into the unicode table
792 
793  args->n_char =
795  plP_esc( PLESC_TEXT_CHAR, args );
796  }
797  else
798  {
799  // Use "unknown" unicode character if string[i+2]
800  // is not in the Greek array.
801  i += 2;
802  skip = 1; // skip is set if we have copied something
803  // into the unicode table
804 
805  args->n_char =
807  plP_esc( PLESC_TEXT_CHAR, args );
808  }
809  break;
810 
811  case 'u':
813  plP_esc( PLESC_CONTROL_CHAR, args );
814  i += 1;
815  skip = 1;
816  break;
817 
818  case 'd':
820  plP_esc( PLESC_CONTROL_CHAR, args );
821  i += 1;
822  skip = 1;
823  break;
824  case 'b':
826  plP_esc( PLESC_CONTROL_CHAR, args );
827  i += 1;
828  skip = 1;
829  break;
830  case '+':
832  plP_esc( PLESC_CONTROL_CHAR, args );
833  i += 1;
834  skip = 1;
835  break;
836  case '-':
838  plP_esc( PLESC_CONTROL_CHAR, args );
839  i += 1;
840  skip = 1;
841  break;
842  }
843  }
844 
845  if ( skip == 0 )
846  {
847  PLUNICODE unichar = 0;
848 #ifdef HAVE_LIBUNICODE
849  const char * ptr = unicode_get_utf8( string + i, &unichar );
850 #else
851  const char * ptr = utf8_to_ucs4( string + i, &unichar );
852 #endif
853  if ( ptr == NULL )
854  {
855  char buf[BUFFER_SIZE];
856  char tmpstring[31];
857  strncpy( tmpstring, string, 30 );
858  tmpstring[30] = '\0';
859  snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
860  tmpstring, strlen( string ) > 30 ? "[...]" : "" );
861  plabort( buf );
862  return;
863  }
864  i += (int) ( ptr - ( string + i ) - 1 );
865 
866  // Search for escesc (an unescaped escape) in the input
867  // string and adjust unicode_buffer accordingly).
868  //
869  if ( string[i] == esc && string[i + 1] == esc )
870  {
871  i++;
872  args->n_char = (PLUNICODE) esc;
873  }
874  else
875  {
876  args->n_char = unichar;
877  }
878  plP_esc( PLESC_TEXT_CHAR, args );
879  }
880  }
881 
882  // Signal the end of text string processing to the driver
883  plP_esc( PLESC_END_TEXT, args );
884 }
885 
886 static
887 void encode_unicode( const char * string, EscText *args )
888 {
889  char esc;
890  PLINT ig;
891  PLUNICODE fci;
892  PLUNICODE orig_fci;
893  unsigned char hexdigit, hexpower;
894  size_t i, j, len;
895  int skip;
896  PLUNICODE code;
897  int idx = -1;
898 
899  // Initialize to an empty string
900  args->unicode_array_len = 0;
901 
902  // this length is only used in the loop
903  // counter, we will work out the length of
904  // the unicode string as we go
905  len = strlen( string );
906 
907  // If the string is empty, return now
908  if ( len == 0 )
909  return;
910 
911  // Get the current escape character
912  plgesc( &esc );
913 
914  // At this stage we will do some translations into unicode, like
915  // conversion to Greek , and will save other translations such as
916  // superscript for the driver to do later on. As we move through
917  // the string and do the translations, we will get
918  // rid of the esc character sequence, just replacing it with
919  // unicode.
920  //
921 
922  // Obtain FCI (font characterization integer) for start of string.
923  plgfci( &fci );
924  orig_fci = fci;
925 
926  // Walk through the string, and convert some stuff to unicode on the fly
927  for ( j = i = 0; i < len; i++ )
928  {
929  skip = 0;
930 
931  if ( string[i] == esc )
932  {
933  // We have an escape character, so we need to look at the
934  // next character to determine what action needs to be taken
935  switch ( string[i + 1] )
936  {
937  case '(': // hershey code
938  i += ( 2 + text2num( &string[i + 2], ')', &code ) );
939  idx = plhershey2unicode( (int) code );
940  args->unicode_array[j++] =
942 
943  // if unicode_buffer[j-1] corresponds to the escape
944  // character must unescape it by appending one more.
945  // This will probably always be necessary since it is
946  // likely unicode_buffer will always have to contain
947  // escape characters that are interpreted by the device
948  // driver.
949  //
950  if ( args->unicode_array[j - 1] == (PLUNICODE) esc )
951  args->unicode_array[j++] = (PLUNICODE) esc;
952  j--;
953  skip = 1;
954  break;
955 
956  case '[': // unicode
957  i += ( 2 + text2num( &string[i + 2], ']', &code ) );
958  args->unicode_array[j++] = code;
959 
960  // if unicode_buffer[j-1] corresponds to the escape
961  // character must unescape it by appending one more.
962  // This will probably always be necessary since it is
963  // likely unicode_buffer will always have to contain
964  // escape characters that are interpreted by the device
965  // driver.
966  //
967  if ( args->unicode_array[j - 1] == (PLUNICODE) esc )
968  args->unicode_array[j++] = (PLUNICODE) esc;
969  j--;
970  skip = 1;
971  break;
972 
973  case '<': // change font
974  if ( '0' <= string[i + 2] && string[i + 2] <= '9' )
975  {
976  i += 2 + text2num( &string[i + 2], '>', &code );
977  if ( code & PL_FCI_MARK )
978  {
979  // code is a complete FCI (font characterization
980  // integer): change FCI to this value.
981  //
982  fci = code;
983  args->unicode_array[j] = fci;
984  skip = 1;
985  }
986  else
987  {
988  // code is not complete FCI. Change
989  // FCI with hex power in rightmost hex
990  // digit and hex digit value in second rightmost
991  // hex digit.
992  //
993  hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK;
994  hexpower = code & PL_FCI_HEXPOWER_MASK;
995  plP_hex2fci( hexdigit, hexpower, &fci );
996  args->unicode_array[j] = fci;
997  skip = 1;
998  }
999  }
1000  else
1001  {
1002  i += text2fci( &string[i + 1], &hexdigit, &hexpower );
1003  if ( hexpower < 7 )
1004  {
1005  plP_hex2fci( hexdigit, hexpower, &fci );
1006  args->unicode_array[j] = fci;
1007  skip = 1;
1008  }
1009  }
1010  break;
1011 
1012  case 'f': // Deprecated Hershey-style font change
1013  case 'F': // Deprecated Hershey-style font change
1014  // We implement an approximate response here so that
1015  // reasonable results are obtained for unicode fonts,
1016  // but this method is deprecated and the #<nnn> or
1017  // #<command string> methods should be used instead
1018  // to change unicode fonts in mid-string.
1019  //
1020  fci = PL_FCI_MARK;
1021  if ( string[i + 2] == 'n' )
1022  {
1023  // medium, upright, sans-serif
1025  }
1026  else if ( string[i + 2] == 'r' )
1027  {
1028  // medium, upright, serif
1030  }
1031  else if ( string[i + 2] == 'i' )
1032  {
1033  // medium, italic, serif
1036  }
1037  else if ( string[i + 2] == 's' )
1038  {
1039  // medium, upright, script
1041  }
1042  else
1043  fci = PL_FCI_IMPOSSIBLE;
1044 
1045  if ( fci != PL_FCI_IMPOSSIBLE )
1046  {
1047  i += 2;
1048  args->unicode_array[j] = fci;
1049  skip = 1;
1050  }
1051  break;
1052 
1053  case 'g': // Greek font
1054  case 'G': // Greek font
1055  // Get the index in the lookup table
1056  // 527 = upper case alpha displacement in Hershey Table
1057  // 627 = lower case alpha displacement in Hershey Table
1058  //
1059 
1060  ig = plP_strpos( plP_greek_mnemonic, string[i + 2] );
1061  if ( ig >= 0 )
1062  {
1063  if ( ig >= 24 )
1064  ig = ig + 100 - 24;
1065  ig = ig + 527;
1066  // Follow pldeco in plsym.c which for
1067  // lower case epsilon, theta, and phi
1068  // substitutes (684, 685, and 686) for
1069  // (631, 634, and 647)
1070  if ( ig == 631 )
1071  ig = 684;
1072  else if ( ig == 634 )
1073  ig = 685;
1074  else if ( ig == 647 )
1075  ig = 686;
1076  idx = (int) plhershey2unicode( ig );
1077  args->unicode_array[j++] =
1079  i += 2;
1080  skip = 1; // skip is set if we have copied something
1081  // into the unicode table
1082  }
1083  else
1084  {
1085  // Use "unknown" unicode character if string[i+2]
1086  // is not in the Greek array.
1087  args->unicode_array[j++] = (PLUNICODE) 0x00;
1088  i += 2;
1089  skip = 1; // skip is set if we have copied something
1090  // into the unicode table
1091  }
1092  j--;
1093  break;
1094  }
1095  }
1096 
1097  if ( skip == 0 )
1098  {
1099  PLUNICODE unichar = 0;
1100 #ifdef HAVE_LIBUNICODE
1101  const char * ptr = unicode_get_utf8( string + i, &unichar );
1102 #else
1103  const char * ptr = utf8_to_ucs4( string + i, &unichar );
1104 #endif
1105  if ( ptr == NULL )
1106  {
1107  char buf[BUFFER_SIZE];
1108  char tmpstring[31];
1109  strncpy( tmpstring, string, 30 );
1110  tmpstring[30] = '\0';
1111  snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
1112  tmpstring, strlen( string ) > 30 ? "[...]" : "" );
1113  plabort( buf );
1114  return;
1115  }
1116  args->unicode_array[j] = unichar;
1117  i += (int) ( ptr - ( string + i ) - 1 );
1118 
1119  // Search for escesc (an unescaped escape) in the input
1120  // string and adjust unicode_buffer accordingly).
1121  //
1122  if ( args->unicode_array[j] == (PLUNICODE) esc
1123  && string[i + 1] == esc )
1124  {
1125  i++;
1126  args->unicode_array[++j] = (PLUNICODE) esc;
1127  }
1128  }
1129  j++;
1130  }
1131 
1132  // Much easier to set the length than
1133  // work it out later :-)
1134  args->unicode_array_len = (short unsigned int) j;
1135 }
1136 
1138 
1139 void
1140 plP_text( PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
1141  PLINT refx, PLINT refy, const char *string )
1142 {
1143  size_t len;
1144 
1145  // First, check if the caller passed an empty string. If it is,
1146  // then we can return now
1147  if ( string == NULL )
1148  return;
1149 
1150  if ( plsc->dev_text ) // Does the device render it's own text ?
1151  {
1152  EscText args;
1153 
1154  args.text_type = PL_STRING_TEXT;
1155  args.base = base;
1156  args.just = just;
1157  args.xform = xform;
1158  args.x = x;
1159  args.y = y;
1160  args.refx = refx;
1161  args.refy = refy;
1162 
1163  // Always store the string passed by the caller, even for unicode
1164  // enabled drivers. The plmeta driver will use this field to store
1165  // the string data in the metafile.
1166  args.string = string;
1167 
1168  // Does the device also understand unicode?
1169  if ( plsc->dev_unicode )
1170  {
1171  if ( plsc->alt_unicode )
1172  {
1173  // We are using the alternate unicode processing
1174  alternate_unicode_processing( string, &args );
1175 
1176  // All text processing is done, so we can exit
1177  return;
1178  }
1179  else
1180  {
1181  // Setup storage for the unicode array and
1182  // process the string to generate the unicode
1183  // representation of it.
1185  encode_unicode( string, &args );
1186 
1187  len = (size_t) args.unicode_array_len;
1188  }
1189  }
1190  else
1191  {
1192  // We are using the char array, NULL out the unicode part
1193  args.unicode_array = NULL;
1194  args.unicode_array_len = 0;
1195 
1196  len = strlen( string );
1197  }
1198 
1199  // If the string is not empty, ask the driver to display it
1200  if ( len > 0 )
1201  plP_esc( PLESC_HAS_TEXT, &args );
1202 
1203 #ifndef DEBUG_TEXT
1204  }
1205  else
1206  {
1207 #endif
1208  plstr( base, xform, refx, refy, string );
1209  }
1210 }
1211 
1212 // convert utf8 string to ucs4 unichar
1213 static const char *
1214 utf8_to_ucs4( const char *ptr, PLUNICODE *unichar )
1215 {
1216  char tmp;
1217  int isFirst = 1;
1218  int cnt = 0;
1219 
1220  do
1221  {
1222  // Get next character in string
1223  tmp = *ptr++;
1224  if ( isFirst ) // First char in UTF8 sequence
1225  {
1226  isFirst = 0;
1227  // Determine length of sequence
1228  if ( (unsigned char) ( tmp & 0x80 ) == 0x00 ) // single char
1229  {
1230  *unichar = (unsigned int) tmp & 0x7F;
1231  cnt = 0;
1232  }
1233  else if ( (unsigned char) ( tmp & 0xE0 ) == 0xC0 ) // 2 chars
1234  {
1235  *unichar = (unsigned int) tmp & 0x1F;
1236  cnt = 1;
1237  }
1238  else if ( (unsigned char) ( tmp & 0xF0 ) == 0xE0 ) // 3 chars
1239  {
1240  *unichar = (unsigned char) tmp & 0x0F;
1241  cnt = 2;
1242  }
1243  else if ( (unsigned char) ( tmp & 0xF8 ) == 0xF0 ) // 4 chars
1244  {
1245  *unichar = (unsigned char) tmp & 0x07;
1246  cnt = 3;
1247  }
1248  else if ( (unsigned char) ( tmp & 0xFC ) == 0xF8 ) // 5 chars
1249  {
1250  *unichar = (unsigned char) tmp & 0x03;
1251  cnt = 4;
1252  }
1253  else if ( (unsigned char) ( tmp & 0xFE ) == 0xFC ) // 6 chars
1254  {
1255  *unichar = (unsigned char) tmp & 0x01;
1256  cnt = 5;
1257  }
1258  else // Malformed
1259  {
1260  ptr = NULL;
1261  cnt = 0;
1262  }
1263  }
1264  else // Subsequent char in UTF8 sequence
1265  {
1266  if ( (unsigned char) ( tmp & 0xC0 ) == 0x80 )
1267  {
1268  *unichar = ( *unichar << 6 ) | ( (unsigned int) tmp & 0x3F );
1269  cnt--;
1270  }
1271  else // Malformed
1272  {
1273  ptr = NULL;
1274  cnt = 0;
1275  }
1276  }
1277  } while ( cnt > 0 );
1278  return ptr;
1279 }
1280 
1281 // convert ucs4 unichar to utf8 string
1282 int
1283 ucs4_to_utf8( PLUNICODE unichar, char *ptr )
1284 {
1285  unsigned char *tmp;
1286  int len;
1287 
1288  tmp = (unsigned char *) ptr;
1289 
1290  if ( ( unichar & 0xffff80 ) == 0 ) // single byte
1291  {
1292  *tmp = (unsigned char) unichar;
1293  tmp++;
1294  len = 1;
1295  }
1296  else if ( ( unichar & 0xfff800 ) == 0 ) // two bytes
1297  {
1298  *tmp = (unsigned char) 0xc0 | (unsigned char) ( unichar >> 6 );
1299  tmp++;
1300  *tmp = (unsigned char) ( 0x80 | (unsigned char) ( unichar & (PLUINT) 0x3f ) );
1301  tmp++;
1302  len = 2;
1303  }
1304  else if ( ( unichar & 0xff0000 ) == 0 ) // three bytes
1305  {
1306  *tmp = (unsigned char) 0xe0 | (unsigned char) ( unichar >> 12 );
1307  tmp++;
1308  *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 6 ) & 0x3f ) );
1309  tmp++;
1310  *tmp = (unsigned char) ( 0x80 | ( (unsigned char) unichar & 0x3f ) );
1311  tmp++;
1312  len = 3;
1313  }
1314  else if ( ( unichar & 0xe0000 ) == 0 ) // four bytes
1315  {
1316  *tmp = (unsigned char) 0xf0 | (unsigned char) ( unichar >> 18 );
1317  tmp++;
1318  *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 12 ) & 0x3f ) );
1319  tmp++;
1320  *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 6 ) & 0x3f ) );
1321  tmp++;
1322  *tmp = (unsigned char) ( 0x80 | (unsigned char) ( unichar & 0x3f ) );
1323  tmp++;
1324  len = 4;
1325  }
1326  else // Illegal coding
1327  {
1328  len = 0;
1329  }
1330  *tmp = '\0';
1331 
1332  return len;
1333 }
1334 
1335 static void
1336 grline( short *x, short *y, PLINT PL_UNUSED( npts ) )
1337 {
1338  char *save_locale = plsave_set_locale();
1339  if ( !plsc->stream_closed )
1340  {
1341  ( *plsc->dispatch_table->pl_line )( (struct PLStream_struct *) plsc,
1342  x[0], y[0], x[1], y[1] );
1343  }
1344  plrestore_locale( save_locale );
1345 }
1346 
1347 static void
1348 grpolyline( short *x, short *y, PLINT npts )
1349 {
1350  char *save_locale = plsave_set_locale();
1351  if ( !plsc->stream_closed )
1352  {
1353  ( *plsc->dispatch_table->pl_polyline )( (struct PLStream_struct *) plsc,
1354  x, y, npts );
1355  }
1356  plrestore_locale( save_locale );
1357 }
1358 
1359 static void
1360 grfill( short *x, short *y, PLINT npts )
1361 {
1362  char * save_locale;
1363  plsc->dev_npts = npts;
1364  plsc->dev_x = x;
1365  plsc->dev_y = y;
1366 
1367  save_locale = plsave_set_locale();
1368  if ( !plsc->stream_closed )
1369  {
1370  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
1371  PLESC_FILL, NULL );
1372  }
1373  plrestore_locale( save_locale );
1374 }
1375 
1376 static void
1377 grgradient( short *x, short *y, PLINT npts )
1378 {
1379  char * save_locale;
1380  plsc->dev_npts = npts;
1381  plsc->dev_x = x;
1382  plsc->dev_y = y;
1383 
1384  save_locale = plsave_set_locale();
1385  if ( !plsc->stream_closed )
1386  {
1387  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
1388  PLESC_GRADIENT, NULL );
1389  }
1390  plrestore_locale( save_locale );
1391 }
1392 
1393 //--------------------------------------------------------------------------
1394 // void difilt
1395 //
1396 // Driver interface filter -- passes all coordinates through a variety
1397 // of filters. These include filters to change :
1398 //
1399 // - mapping of meta to physical coordinates
1400 // - plot orientation
1401 // - window into plot (zooms)
1402 // - window into device (i.e set margins)
1403 //
1404 // The filters are applied in the order specified above. Because the
1405 // orientation change comes first, subsequent window specifications affect
1406 // the new coordinates (i.e. after a 90 degree flip, what was x is now y).
1407 // This is the only way that makes sense from a graphical interface
1408 // (e.g. TCL/TK driver).
1409 //
1410 // Where appropriate, the page clip limits are modified.
1411 //--------------------------------------------------------------------------
1412 
1413 void
1414 difilt( PLINT *xsc, PLINT *ysc, PLINT npts,
1415  PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma )
1416 {
1417  PLINT i, x, y;
1418 
1419 // Map meta coordinates to physical coordinates
1420 
1421  if ( plsc->difilt & PLDI_MAP )
1422  {
1423  for ( i = 0; i < npts; i++ )
1424  {
1425  xsc[i] = (PLINT) ( plsc->dimxax * xsc[i] + plsc->dimxb );
1426  ysc[i] = (PLINT) ( plsc->dimyay * ysc[i] + plsc->dimyb );
1427  }
1428  }
1429 
1430 // Change orientation
1431 
1432  if ( plsc->difilt & PLDI_ORI )
1433  {
1434  for ( i = 0; i < npts; i++ )
1435  {
1436  x = (PLINT) ( plsc->dioxax * xsc[i] + plsc->dioxay * ysc[i] + plsc->dioxb );
1437  y = (PLINT) ( plsc->dioyax * xsc[i] + plsc->dioyay * ysc[i] + plsc->dioyb );
1438  xsc[i] = x;
1439  ysc[i] = y;
1440  }
1441  }
1442 
1443 // Change window into plot space
1444 
1445  if ( plsc->difilt & PLDI_PLT )
1446  {
1447  for ( i = 0; i < npts; i++ )
1448  {
1449  xsc[i] = (PLINT) ( plsc->dipxax * xsc[i] + plsc->dipxb );
1450  ysc[i] = (PLINT) ( plsc->dipyay * ysc[i] + plsc->dipyb );
1451  }
1452  }
1453 
1454 // Change window into device space and set clip limits
1455 // (this is the only filter that modifies them)
1456 
1457  if ( plsc->difilt & PLDI_DEV )
1458  {
1459  for ( i = 0; i < npts; i++ )
1460  {
1461  xsc[i] = (PLINT) ( plsc->didxax * xsc[i] + plsc->didxb );
1462  ysc[i] = (PLINT) ( plsc->didyay * ysc[i] + plsc->didyb );
1463  }
1464  *clpxmi = plsc->diclpxmi;
1465  *clpxma = plsc->diclpxma;
1466  *clpymi = plsc->diclpymi;
1467  *clpyma = plsc->diclpyma;
1468  }
1469  else
1470  {
1471  *clpxmi = plsc->phyxmi;
1472  *clpxma = plsc->phyxma;
1473  *clpymi = plsc->phyymi;
1474  *clpyma = plsc->phyyma;
1475  }
1476 }
1477 
1478 
1479 // Function is unused except for commented out image code
1480 // If / when that is fixed, then reinstate this function.
1481 // Needs a prototype and the casting fixed.
1482 //
1483 // void
1484 // sdifilt( short *xscl, short *yscl, PLINT npts,
1485 // PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma )
1486 // {
1487 // int i;
1488 // short x, y;
1489 
1490 // // Map meta coordinates to physical coordinates
1491 
1492 // if ( plsc->difilt & PLDI_MAP )
1493 // {
1494 // for ( i = 0; i < npts; i++ )
1495 // {
1496 // xscl[i] = (PLINT) ( plsc->dimxax * xscl[i] + plsc->dimxb );
1497 // yscl[i] = (PLINT) ( plsc->dimyay * yscl[i] + plsc->dimyb );
1498 // }
1499 // }
1500 
1501 // // Change orientation
1502 
1503 // if ( plsc->difilt & PLDI_ORI )
1504 // {
1505 // for ( i = 0; i < npts; i++ )
1506 // {
1507 // x = (PLINT) ( plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb );
1508 // y = (PLINT) ( plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb );
1509 // xscl[i] = x;
1510 // yscl[i] = y;
1511 // }
1512 // }
1513 
1514 // // Change window into plot space
1515 
1516 // if ( plsc->difilt & PLDI_PLT )
1517 // {
1518 // for ( i = 0; i < npts; i++ )
1519 // {
1520 // xscl[i] = (PLINT) ( plsc->dipxax * xscl[i] + plsc->dipxb );
1521 // yscl[i] = (PLINT) ( plsc->dipyay * yscl[i] + plsc->dipyb );
1522 // }
1523 // }
1524 
1525 // // Change window into device space and set clip limits
1526 // // (this is the only filter that modifies them)
1527 
1528 // if ( plsc->difilt & PLDI_DEV )
1529 // {
1530 // for ( i = 0; i < npts; i++ )
1531 // {
1532 // xscl[i] = (PLINT) ( plsc->didxax * xscl[i] + plsc->didxb );
1533 // yscl[i] = (PLINT) ( plsc->didyay * yscl[i] + plsc->didyb );
1534 // }
1535 // *clpxmi = (PLINT) ( plsc->diclpxmi );
1536 // *clpxma = (PLINT) ( plsc->diclpxma );
1537 // *clpymi = (PLINT) ( plsc->diclpymi );
1538 // *clpyma = (PLINT) ( plsc->diclpyma );
1539 // }
1540 // else
1541 // {
1542 // *clpxmi = plsc->phyxmi;
1543 // *clpxma = plsc->phyxma;
1544 // *clpymi = plsc->phyymi;
1545 // *clpyma = plsc->phyyma;
1546 // }
1547 // }
1548 
1549 //--------------------------------------------------------------------------
1550 // void difilt_clip
1551 //
1552 // This provides the transformed text clipping region for the benefit of
1553 // those drivers that render their own text.
1554 //--------------------------------------------------------------------------
1555 
1556 void
1557 difilt_clip( PLINT *x_coords, PLINT *y_coords )
1558 {
1559  PLINT x1c, x2c, y1c, y2c;
1560 
1561  x1c = plsc->clpxmi;
1562  y1c = plsc->clpymi;
1563  x2c = plsc->clpxma;
1564  y2c = plsc->clpyma;
1565  x_coords[0] = x1c;
1566  x_coords[1] = x1c;
1567  x_coords[2] = x2c;
1568  x_coords[3] = x2c;
1569  y_coords[0] = y1c;
1570  y_coords[1] = y2c;
1571  y_coords[2] = y2c;
1572  y_coords[3] = y1c;
1573  difilt( x_coords, y_coords, 4, &x1c, &x2c, &y1c, &y2c );
1574 }
1575 
1576 
1577 //--------------------------------------------------------------------------
1578 // void pldi_ini
1579 //
1580 // Updates driver interface, making sure everything is in order.
1581 // Even if filter is not being used, the defaults need to be set up.
1582 //--------------------------------------------------------------------------
1583 
1584 static void
1586 {
1587  plsc->dipxmin = 0.0;
1588  plsc->dipxmax = 1.0;
1589  plsc->dipymin = 0.0;
1590  plsc->dipymax = 1.0;
1591 }
1592 
1593 static void
1595 {
1596  plsc->mar = 0.0;
1597  plsc->aspect = 0.0;
1598  plsc->jx = 0.0;
1599  plsc->jy = 0.0;
1600 }
1601 
1602 static void
1604 {
1605  plsc->diorot = 0.;
1606 }
1607 
1608 static void
1609 pldi_ini( void )
1610 {
1611  if ( plsc->level >= 1 )
1612  {
1613  if ( plsc->plbuf_write )
1614  plbuf_di( plsc );
1615  if ( plsc->difilt & PLDI_MAP ) // Coordinate mapping
1616  calc_dimap();
1617 
1618  if ( plsc->difilt & PLDI_ORI ) // Orientation
1619  calc_diori();
1620  else
1621  setdef_diori();
1622 
1623  if ( plsc->difilt & PLDI_PLT ) // Plot window
1624  calc_diplt();
1625  else
1626  setdef_diplt();
1627 
1628  if ( plsc->difilt & PLDI_DEV ) // Device window
1629  calc_didev();
1630  else
1631  setdef_didev();
1632  }
1633 }
1634 
1635 //--------------------------------------------------------------------------
1636 // void pldid2pc
1637 //
1638 // Converts input values from relative device coordinates to relative plot
1639 // coordinates. This function must be called when selecting a plot window
1640 // from a display driver, since the coordinates chosen by the user are
1641 // necessarily device-specific.
1642 //--------------------------------------------------------------------------
1643 
1644 void
1646 {
1647  PLFLT pxmin, pymin, pxmax, pymax;
1648  PLFLT sxmin, symin, sxmax, symax;
1649  PLFLT rxmin, rymin, rxmax, rymax;
1650 
1651  if ( plsc->difilt & PLDI_DEV )
1652  {
1653  pldebug( "pldid2pc",
1654  "Relative device coordinates (in): %f, %f, %f, %f\n",
1655  *xmin, *ymin, *xmax, *ymax );
1656 
1657  pxmin = plP_dcpcx( *xmin );
1658  pymin = plP_dcpcy( *ymin );
1659  pxmax = plP_dcpcx( *xmax );
1660  pymax = plP_dcpcy( *ymax );
1661 
1662  sxmin = ( pxmin - plsc->didxb ) / plsc->didxax;
1663  symin = ( pymin - plsc->didyb ) / plsc->didyay;
1664  sxmax = ( pxmax - plsc->didxb ) / plsc->didxax;
1665  symax = ( pymax - plsc->didyb ) / plsc->didyay;
1666 
1667  rxmin = plP_pcdcx( (PLINT) sxmin );
1668  rymin = plP_pcdcy( (PLINT) symin );
1669  rxmax = plP_pcdcx( (PLINT) sxmax );
1670  rymax = plP_pcdcy( (PLINT) symax );
1671 
1672  *xmin = ( rxmin < 0 ) ? 0 : rxmin;
1673  *xmax = ( rxmax > 1 ) ? 1 : rxmax;
1674  *ymin = ( rymin < 0 ) ? 0 : rymin;
1675  *ymax = ( rymax > 1 ) ? 1 : rymax;
1676 
1677  pldebug( "pldid2pc",
1678  "Relative plot coordinates (out): %f, %f, %f, %f\n",
1679  rxmin, rymin, rxmax, rymax );
1680  }
1681 }
1682 
1683 //--------------------------------------------------------------------------
1684 // void pldip2dc
1685 //
1686 // Converts input values from relative plot coordinates to relative
1687 // device coordinates.
1688 //--------------------------------------------------------------------------
1689 
1690 void
1692 {
1693  PLFLT pxmin, pymin, pxmax, pymax;
1694  PLFLT sxmin, symin, sxmax, symax;
1695  PLFLT rxmin, rymin, rxmax, rymax;
1696 
1697  if ( plsc->difilt & PLDI_DEV )
1698  {
1699  pldebug( "pldip2pc",
1700  "Relative plot coordinates (in): %f, %f, %f, %f\n",
1701  *xmin, *ymin, *xmax, *ymax );
1702 
1703  pxmin = plP_dcpcx( *xmin );
1704  pymin = plP_dcpcy( *ymin );
1705  pxmax = plP_dcpcx( *xmax );
1706  pymax = plP_dcpcy( *ymax );
1707 
1708  sxmin = pxmin * plsc->didxax + plsc->didxb;
1709  symin = pymin * plsc->didyay + plsc->didyb;
1710  sxmax = pxmax * plsc->didxax + plsc->didxb;
1711  symax = pymax * plsc->didyay + plsc->didyb;
1712 
1713  rxmin = plP_pcdcx( (PLINT) sxmin );
1714  rymin = plP_pcdcy( (PLINT) symin );
1715  rxmax = plP_pcdcx( (PLINT) sxmax );
1716  rymax = plP_pcdcy( (PLINT) symax );
1717 
1718  *xmin = ( rxmin < 0 ) ? 0 : rxmin;
1719  *xmax = ( rxmax > 1 ) ? 1 : rxmax;
1720  *ymin = ( rymin < 0 ) ? 0 : rymin;
1721  *ymax = ( rymax > 1 ) ? 1 : rymax;
1722 
1723  pldebug( "pldip2pc",
1724  "Relative device coordinates (out): %f, %f, %f, %f\n",
1725  rxmin, rymin, rxmax, rymax );
1726  }
1727 }
1728 
1729 //--------------------------------------------------------------------------
1730 // void plsdiplt
1731 //
1732 // Set window into plot space
1733 //--------------------------------------------------------------------------
1734 
1735 void
1737 {
1738  plsc->dipxmin = ( xmin < xmax ) ? xmin : xmax;
1739  plsc->dipxmax = ( xmin < xmax ) ? xmax : xmin;
1740  plsc->dipymin = ( ymin < ymax ) ? ymin : ymax;
1741  plsc->dipymax = ( ymin < ymax ) ? ymax : ymin;
1742 
1743  if ( xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1. )
1744  {
1745  plsc->difilt &= ~PLDI_PLT;
1746  return;
1747  }
1748 
1749  plsc->difilt |= PLDI_PLT;
1750  pldi_ini();
1751 }
1752 
1753 //--------------------------------------------------------------------------
1754 // void plsdiplz
1755 //
1756 // Set window into plot space incrementally (zoom)
1757 //--------------------------------------------------------------------------
1758 
1759 void
1761 {
1762  if ( plsc->difilt & PLDI_PLT )
1763  {
1764  xmin = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmin;
1765  ymin = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymin;
1766  xmax = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmax;
1767  ymax = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymax;
1768  }
1769 
1770  plsdiplt( xmin, ymin, xmax, ymax );
1771 }
1772 
1773 //--------------------------------------------------------------------------
1774 // void calc_diplt
1775 //
1776 // Calculate transformation coefficients to set window into plot space.
1777 //
1778 // Note: if driver has requested to handle these commands itself, we must
1779 // send the appropriate escape command. If the driver succeeds it will
1780 // cancel the filter operation. The command is deferred until this point
1781 // to ensure that the driver has been initialized.
1782 //--------------------------------------------------------------------------
1783 
1784 static void
1785 calc_diplt( void )
1786 {
1787  PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
1788 
1789  if ( plsc->dev_di )
1790  {
1791  char *save_locale = plsave_set_locale();
1792  if ( !plsc->stream_closed )
1793  {
1794  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
1795  PLESC_DI, NULL );
1796  }
1797  plrestore_locale( save_locale );
1798  }
1799 
1800  if ( !( plsc->difilt & PLDI_PLT ) )
1801  return;
1802 
1803  pxmin = plP_dcpcx( plsc->dipxmin );
1804  pxmax = plP_dcpcx( plsc->dipxmax );
1805  pymin = plP_dcpcy( plsc->dipymin );
1806  pymax = plP_dcpcy( plsc->dipymax );
1807 
1808  pxlen = pxmax - pxmin;
1809  pylen = pymax - pymin;
1810  pxlen = MAX( 1, pxlen );
1811  pylen = MAX( 1, pylen );
1812 
1813  plsc->dipxax = plsc->phyxlen / (double) pxlen;
1814  plsc->dipyay = plsc->phyylen / (double) pylen;
1815  plsc->dipxb = plsc->phyxmi - plsc->dipxax * pxmin;
1816  plsc->dipyb = plsc->phyymi - plsc->dipyay * pymin;
1817 }
1818 
1819 //--------------------------------------------------------------------------
1820 // void plgdiplt
1821 //
1822 // Retrieve current window into plot space
1823 //--------------------------------------------------------------------------
1824 
1825 void
1826 c_plgdiplt( PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax )
1827 {
1828  *p_xmin = plsc->dipxmin;
1829  *p_xmax = plsc->dipxmax;
1830  *p_ymin = plsc->dipymin;
1831  *p_ymax = plsc->dipymax;
1832 }
1833 
1834 //--------------------------------------------------------------------------
1835 // void plsdidev
1836 //
1837 // Set window into device space using margin, aspect ratio, and
1838 // justification. If you want to just use the previous value for any of
1839 // these, just pass in the magic value PL_NOTSET.
1840 //
1841 // It is unlikely that one should ever need to change the aspect ratio
1842 // but it's in there for completeness.
1843 //--------------------------------------------------------------------------
1844 
1845 void
1846 c_plsdidev( PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy )
1847 {
1848  plsetvar( plsc->mar, mar );
1849  plsetvar( plsc->aspect, aspect );
1850  plsetvar( plsc->jx, jx );
1851  plsetvar( plsc->jy, jy );
1852 
1853  if ( mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
1854  !( plsc->difilt & PLDI_ORI ) )
1855  {
1856  plsc->difilt &= ~PLDI_DEV;
1857  return;
1858  }
1859 
1860  plsc->difilt |= PLDI_DEV;
1861  pldi_ini();
1862 }
1863 
1864 //--------------------------------------------------------------------------
1865 // void calc_didev
1866 //
1867 // Calculate transformation coefficients to set window into device space.
1868 // Calculates relative window bounds and calls plsdidxy to finish the job.
1869 //--------------------------------------------------------------------------
1870 
1871 static void
1872 calc_didev( void )
1873 {
1874  PLFLT lx, ly, aspect, aspdev;
1875  PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
1876  PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
1877 
1878  if ( plsc->dev_di )
1879  {
1880  char *save_locale = plsave_set_locale();
1881  if ( !plsc->stream_closed )
1882  {
1883  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
1884  PLESC_DI, NULL );
1885  }
1886  plrestore_locale( save_locale );
1887  }
1888 
1889  if ( !( plsc->difilt & PLDI_DEV ) )
1890  return;
1891 
1892 // Calculate aspect ratio of physical device
1893 
1894  lx = plsc->phyxlen / plsc->xpmm;
1895  ly = plsc->phyylen / plsc->ypmm;
1896  aspdev = lx / ly;
1897 
1898  if ( plsc->difilt & PLDI_ORI )
1899  aspect = plsc->aspori;
1900  else
1901  aspect = plsc->aspect;
1902 
1903  if ( aspect <= 0. )
1904  aspect = plsc->aspdev;
1905 
1906 // Failsafe
1907 
1908  plsc->mar = ( plsc->mar > 0.5 ) ? 0.5 : plsc->mar;
1909  plsc->mar = ( plsc->mar < 0.0 ) ? 0.0 : plsc->mar;
1910  plsc->jx = ( plsc->jx > 0.5 ) ? 0.5 : plsc->jx;
1911  plsc->jx = ( plsc->jx < -0.5 ) ? -0.5 : plsc->jx;
1912  plsc->jy = ( plsc->jy > 0.5 ) ? 0.5 : plsc->jy;
1913  plsc->jy = ( plsc->jy < -0.5 ) ? -0.5 : plsc->jy;
1914 
1915 // Relative device coordinates that neutralize aspect ratio difference
1916 
1917  xlen = ( aspect < aspdev ) ? ( aspect / aspdev ) : 1.0;
1918  ylen = ( aspect < aspdev ) ? 1.0 : ( aspdev / aspect );
1919 
1920  xlen *= ( 1.0 - 2. * plsc->mar );
1921  ylen *= ( 1.0 - 2. * plsc->mar );
1922 
1923  xmin = ( 1. - xlen ) * ( 0.5 + plsc->jx );
1924  xmax = xmin + xlen;
1925 
1926  ymin = ( 1. - ylen ) * ( 0.5 + plsc->jy );
1927  ymax = ymin + ylen;
1928 
1929 // Calculate transformation coefficients
1930 
1931  pxmin = plP_dcpcx( xmin );
1932  pxmax = plP_dcpcx( xmax );
1933  pymin = plP_dcpcy( ymin );
1934  pymax = plP_dcpcy( ymax );
1935 
1936  pxlen = pxmax - pxmin;
1937  pylen = pymax - pymin;
1938  pxlen = MAX( 1, pxlen );
1939  pylen = MAX( 1, pylen );
1940 
1941  plsc->didxax = pxlen / (double) plsc->phyxlen;
1942  plsc->didyay = pylen / (double) plsc->phyylen;
1943  plsc->didxb = pxmin - plsc->didxax * plsc->phyxmi;
1944  plsc->didyb = pymin - plsc->didyay * plsc->phyymi;
1945 
1946 // Set clip limits to conform to new page size
1947 
1948  plsc->diclpxmi = (PLINT) ( plsc->didxax * plsc->phyxmi + plsc->didxb );
1949  plsc->diclpxma = (PLINT) ( plsc->didxax * plsc->phyxma + plsc->didxb );
1950  plsc->diclpymi = (PLINT) ( plsc->didyay * plsc->phyymi + plsc->didyb );
1951  plsc->diclpyma = (PLINT) ( plsc->didyay * plsc->phyyma + plsc->didyb );
1952 }
1953 
1954 //--------------------------------------------------------------------------
1955 // void plgdidev
1956 //
1957 // Retrieve current window into device space
1958 //--------------------------------------------------------------------------
1959 
1960 void
1961 c_plgdidev( PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy )
1962 {
1963  *p_mar = plsc->mar;
1964  *p_aspect = plsc->aspect;
1965  *p_jx = plsc->jx;
1966  *p_jy = plsc->jy;
1967 }
1968 
1969 //--------------------------------------------------------------------------
1970 // void plsdiori
1971 //
1972 // Set plot orientation, specifying rotation in units of pi/2.
1973 //--------------------------------------------------------------------------
1974 
1975 void
1977 {
1978  plsc->diorot = rot;
1979  if ( rot == 0. )
1980  {
1981  plsc->difilt &= ~PLDI_ORI;
1982  pldi_ini();
1983  return;
1984  }
1985 
1986  plsc->difilt |= PLDI_ORI;
1987  pldi_ini();
1988 }
1989 
1990 //--------------------------------------------------------------------------
1991 // void calc_diori
1992 //
1993 // Calculate transformation coefficients to arbitrarily orient plot.
1994 // Preserve aspect ratios so the output doesn't suck.
1995 //--------------------------------------------------------------------------
1996 
1997 static void
1998 calc_diori( void )
1999 {
2000  PLFLT cost, sint;
2001  PLFLT x0, y0, lx, ly, aspect;
2002  PLFLT affine_result[NAFFINE], affine_left[NAFFINE];
2003 
2004  if ( plsc->dev_di )
2005  {
2006  char *save_locale = plsave_set_locale();
2007  if ( !plsc->stream_closed )
2008  {
2009  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
2010  PLESC_DI, NULL );
2011  }
2012  plrestore_locale( save_locale );
2013  }
2014 
2015  if ( !( plsc->difilt & PLDI_ORI ) )
2016  return;
2017 
2018 // Center point of rotation
2019 
2020  x0 = ( plsc->phyxma + plsc->phyxmi ) / 2.;
2021  y0 = ( plsc->phyyma + plsc->phyymi ) / 2.;
2022 
2023 // Rotation
2024 
2025  cost = ABS( cos( plsc->diorot * PI / 2. ) );
2026  sint = ABS( sin( plsc->diorot * PI / 2. ) );
2027 
2028 // Flip aspect ratio as necessary. Grungy but I don't see a better way
2029 
2030  aspect = plsc->aspect;
2031  if ( aspect == 0. )
2032  aspect = plsc->aspdev;
2033 
2034  if ( plsc->freeaspect )
2035  plsc->aspori = aspect;
2036  else
2037  plsc->aspori = ( aspect * cost + sint ) / ( aspect * sint + cost );
2038 
2039  if ( !( plsc->difilt & PLDI_DEV ) )
2040  {
2041  plsc->difilt |= PLDI_DEV;
2042  setdef_didev();
2043  }
2044  calc_didev();
2045 
2046  // Compute scale factors for relative device coordinates. Only
2047  // the aspect ratio of lx to ly matters. Note, plsc->phyxlen and
2048  // plsc->phyylen are in PLplot core library coordinates and don't
2049  // know anything about device coordinates which are likely to have
2050  // a quite different aspect ratio. So to correct between the two
2051  // coordinate systems must divide plsc->phyxlen/plsc->phyylen by
2052  // plsc->aspori.
2053 
2054  // N.B. comment out this correction because causes other issues.
2055 
2056  //lx = plsc->phyxlen/plsc->aspori;
2057  lx = plsc->phyxlen;
2058  ly = plsc->phyylen;
2059 
2060 // Transformation coefficients
2061 
2062  //
2063  // plsc->dioxax = r11;
2064  // plsc->dioxay = r21 * ( lx / ly );
2065  // plsc->dioxb = ( 1. - r11 ) * x0 - r21 * y0 * ( lx / ly );
2066  //
2067  // plsc->dioyax = r12 * ( ly / lx );
2068  // plsc->dioyay = r22;
2069  // plsc->dioyb = ( 1. - r22 ) * y0 - r12 * x0 * ( ly / lx );
2070  //
2071 
2072  // Calculate affine transformation as product of translate to middle
2073  // of device, scale to relative device coordinates, rotate, unscale
2074  // to physical coordinates, untranslate to original zero point.
2075  plP_affine_translate( affine_result, x0, y0 );
2076  plP_affine_scale( affine_left, lx, ly );
2077  plP_affine_multiply( affine_result, affine_left, affine_result );
2078  plP_affine_rotate( affine_left, plsc->diorot * 90. );
2079  plP_affine_multiply( affine_result, affine_left, affine_result );
2080  plP_affine_scale( affine_left, 1. / lx, 1. / ly );
2081  plP_affine_multiply( affine_result, affine_left, affine_result );
2082  plP_affine_translate( affine_left, -x0, -y0 );
2083  plP_affine_multiply( affine_result, affine_left, affine_result );
2084  plsc->dioxax = affine_result[0];
2085  plsc->dioxay = affine_result[2];
2086  plsc->dioxb = affine_result[4];
2087  plsc->dioyax = affine_result[1];
2088  plsc->dioyay = affine_result[3];
2089  plsc->dioyb = affine_result[5];
2090 }
2091 
2092 //--------------------------------------------------------------------------
2093 // void plgdiori
2094 //
2095 // Get plot orientation
2096 //--------------------------------------------------------------------------
2097 
2098 void
2100 {
2101  *p_rot = plsc->diorot;
2102 }
2103 
2104 //--------------------------------------------------------------------------
2105 // void plsdimap
2106 //
2107 // Set up transformation from metafile coordinates. The size of the plot is
2108 // scaled so as to preserve aspect ratio. This isn't intended to be a
2109 // general-purpose facility just yet (not sure why the user would need it,
2110 // for one).
2111 //--------------------------------------------------------------------------
2112 
2113 void
2114 c_plsdimap( PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
2115  PLFLT dimxpmm, PLFLT dimypmm )
2116 {
2117  plsetvar( plsc->dimxmin, dimxmin );
2118  plsetvar( plsc->dimxmax, dimxmax );
2119  plsetvar( plsc->dimymin, dimymin );
2120  plsetvar( plsc->dimymax, dimymax );
2121  plsetvar( plsc->dimxpmm, dimxpmm );
2122  plsetvar( plsc->dimypmm, dimypmm );
2123 
2124  plsc->difilt |= PLDI_MAP;
2125  pldi_ini();
2126 }
2127 
2128 //--------------------------------------------------------------------------
2129 // void calc_dimap
2130 //
2131 // Set up transformation from metafile coordinates. The size of the plot is
2132 // scaled so as to preserve aspect ratio. This isn't intended to be a
2133 // general-purpose facility just yet (not sure why the user would need it,
2134 // for one).
2135 //--------------------------------------------------------------------------
2136 
2137 static void
2139 {
2140  PLFLT lx, ly;
2141  PLINT pxmin, pxmax, pymin, pymax;
2142  PLFLT dimxlen, dimylen, pxlen, pylen;
2143 
2144  if ( ( plsc->dimxmin == plsc->phyxmi ) && ( plsc->dimxmax == plsc->phyxma ) &&
2145  ( plsc->dimymin == plsc->phyymi ) && ( plsc->dimymax == plsc->phyyma ) &&
2146  ( plsc->dimxpmm == plsc->xpmm ) && ( plsc->dimypmm == plsc->ypmm ) )
2147  {
2148  plsc->difilt &= ~PLDI_MAP;
2149  return;
2150  }
2151 
2152 // Set default aspect ratio
2153 
2154  lx = ( plsc->dimxmax - plsc->dimxmin + 1 ) / plsc->dimxpmm;
2155  ly = ( plsc->dimymax - plsc->dimymin + 1 ) / plsc->dimypmm;
2156 
2157  plsc->aspdev = lx / ly;
2158 
2159 // Build transformation to correct physical coordinates
2160 
2161  dimxlen = plsc->dimxmax - plsc->dimxmin;
2162  dimylen = plsc->dimymax - plsc->dimymin;
2163 
2164  pxmin = plsc->phyxmi;
2165  pxmax = plsc->phyxma;
2166  pymin = plsc->phyymi;
2167  pymax = plsc->phyyma;
2168  pxlen = pxmax - pxmin;
2169  pylen = pymax - pymin;
2170 
2171  plsc->dimxax = pxlen / dimxlen;
2172  plsc->dimyay = pylen / dimylen;
2173  plsc->dimxb = pxmin - pxlen * plsc->dimxmin / dimxlen;
2174  plsc->dimyb = pymin - pylen * plsc->dimymin / dimylen;
2175 }
2176 
2177 //--------------------------------------------------------------------------
2178 // void plflush()
2179 //
2180 // Flushes the output stream. Use sparingly, if at all.
2181 //--------------------------------------------------------------------------
2182 
2183 void
2184 c_plflush( void )
2185 {
2186  if ( plsc->dev_flush )
2187  {
2188  char *save_locale = plsave_set_locale();
2189  if ( !plsc->stream_closed )
2190  {
2191  ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
2192  PLESC_FLUSH, NULL );
2193  }
2194  plrestore_locale( save_locale );
2195  }
2196  else
2197  {
2198  if ( plsc->OutFile != NULL )
2199  fflush( plsc->OutFile );
2200  }
2201 }
2202 
2203 //--------------------------------------------------------------------------
2204 // Startup routines.
2205 //--------------------------------------------------------------------------
2206 
2207 //--------------------------------------------------------------------------
2208 // void pllib_init()
2209 //
2210 // Initialize library. Called internally by every startup routine.
2211 // Everything you want to always be initialized before plinit() is called
2212 // you should put here. E.g. dispatch table setup, rcfile read, etc.
2213 //--------------------------------------------------------------------------
2214 
2215 void
2217 {
2218  if ( lib_initialized )
2219  return;
2220  lib_initialized = 1;
2221 
2222 #ifdef ENABLE_DYNDRIVERS
2223 // Create libltdl resources
2224  lt_dlinit();
2225 #endif
2226 
2227 // Initialize the dispatch table with the info from the static drivers table
2228 // and the available dynamic drivers.
2229 
2231 }
2232 
2233 //--------------------------------------------------------------------------
2234 // void plstar(nx, ny)
2235 //
2236 // Initialize PLplot, passing in the windows/page settings.
2237 //--------------------------------------------------------------------------
2238 
2239 void
2241 {
2242  pllib_init();
2243 
2244  if ( plsc->level != 0 )
2245  plend1();
2246 
2247  plssub( nx, ny );
2248 
2249  c_plinit();
2250 }
2251 
2252 //--------------------------------------------------------------------------
2253 // void plstart(devname, nx, ny)
2254 //
2255 // Initialize PLplot, passing the device name and windows/page settings.
2256 //--------------------------------------------------------------------------
2257 
2258 void
2259 c_plstart( const char *devname, PLINT nx, PLINT ny )
2260 {
2261  pllib_init();
2262 
2263  if ( plsc->level != 0 )
2264  plend1();
2265 
2266  plssub( nx, ny );
2267  plsdev( devname );
2268 
2269  c_plinit();
2270 }
2271 
2272 //--------------------------------------------------------------------------
2273 // void plinit()
2274 //
2275 // Initializes PLplot, using preset or default options.
2276 //--------------------------------------------------------------------------
2277 
2278 void
2279 c_plinit( void )
2280 {
2281  PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
2282 
2283  pllib_init();
2284 
2285  if ( plsc->level != 0 )
2286  plend1();
2287 
2288 // Set stream number
2289 
2290  plsc->ipls = ipls;
2291 
2292 // Set up devices
2293 
2294  pllib_devinit();
2295 
2296 // Auxiliary stream setup
2297 
2298  plstrm_init();
2299 
2300 // Set title for window to a sensible default if not defined
2301  if ( plsc->plwindow == NULL )
2302  {
2303  if ( plsc->program )
2304  {
2305  if ( ( plsc->plwindow = (char *) malloc( (size_t) ( 1 + strlen( plsc->program ) ) * sizeof ( char ) ) ) == NULL )
2306  {
2307  plexit( "plinit: Insufficient memory" );
2308  }
2309  strcpy( plsc->plwindow, plsc->program );
2310  }
2311  else
2312  {
2313  if ( ( plsc->plwindow = (char *) malloc( (size_t) 7 * sizeof ( char ) ) ) == NULL )
2314  {
2315  plexit( "plinit: Insufficient memory" );
2316  }
2317  strcpy( plsc->plwindow, "PLplot" );
2318  }
2319  }
2320 
2321 // Initialize device & first page
2322 
2323  plP_init();
2324  plP_bop();
2325  plsc->level = 1;
2326 
2327 
2328 // The driver options are freed after driver initialisation,
2329 // since it is assumed that in this function options are
2330 // processed and stored somewhere else. For further driver
2331 // initialisations (e.g. copy stream) there are no driver
2332 // options defined.
2333 
2334  plP_FreeDrvOpts();
2335 
2336 // Calculate factor such that the character aspect ratio is preserved
2337 // when the overall aspect ratio is changed, i.e., if portrait mode is
2338 // requested (only honored for subset of drivers) or if the aspect ratio
2339 // is specified in any way, or if a 90 deg rotation occurs with
2340 // -freeaspect.
2341 
2342 // Case where plsc->aspect has a value.... (e.g., -a aspect on the
2343 // command line or 2nd parameter of plsdidev specified)
2344  if ( plsc->aspect > 0. )
2345  {
2346  lx = plsc->phyxlen / plsc->xpmm;
2347  ly = plsc->phyylen / plsc->ypmm;
2348  aspect_old = lx / ly;
2349  aspect_new = plsc->aspect;
2350  plsc->caspfactor = sqrt( aspect_old / aspect_new );
2351  }
2352 // Case of 90 deg rotations with -freeaspect (this is also how portrait
2353 // mode is implemented for the drivers that honor -portrait).
2354  else if ( plsc->freeaspect && ABS( cos( plsc->diorot * PI / 2. ) ) <= 1.e-5 )
2355  {
2356  lx = plsc->phyxlen / plsc->xpmm;
2357  ly = plsc->phyylen / plsc->ypmm;
2358  aspect_old = lx / ly;
2359  aspect_new = ly / lx;
2360  plsc->caspfactor = sqrt( aspect_old / aspect_new );
2361  }
2362 
2363  else
2364  plsc->caspfactor = 1.;
2365 
2366 // Load fonts
2367 
2368  plsc->cfont = 1;
2369  plfntld( initfont );
2370 
2371 // Set up subpages
2372 
2373  plP_subpInit();
2374 
2375 // Set up number of allowed digits before switching to scientific notation
2376 // The user can always change this
2377 
2378  if ( plsc->xdigmax == 0 )
2379  plsc->xdigmax = 4;
2380 
2381  if ( plsc->ydigmax == 0 )
2382  plsc->ydigmax = 4;
2383 
2384  if ( plsc->zdigmax == 0 )
2385  plsc->zdigmax = 3;
2386 
2387  if ( plsc->timefmt == NULL )
2388  c_pltimefmt( "%c" );
2389 
2390  // Use default transformation between continuous and broken-down time
2391  // (and vice versa) if the transformation has not yet been defined
2392  // for this stream.
2393  if ( plsc->qsasconfig == NULL )
2394  c_plconfigtime( 0., 0., 0., 0x0, 0, 0, 0, 0, 0, 0, 0. );
2395 
2396 // Switch to graphics mode and set color and arrow style
2397 
2398  plgra();
2399  plcol0( 1 );
2400 
2401  pllsty( 1 );
2402  plpsty( 0 );
2403 
2404  // Set up default arrow style;
2405  plsvect( NULL, NULL, 6, 0 );
2406 
2407 // Set clip limits.
2408 
2409  plsc->clpxmi = plsc->phyxmi;
2410  plsc->clpxma = plsc->phyxma;
2411  plsc->clpymi = plsc->phyymi;
2412  plsc->clpyma = plsc->phyyma;
2413 
2414 // Page aspect ratio.
2415 
2416  lx = plsc->phyxlen / plsc->xpmm;
2417  ly = plsc->phyylen / plsc->ypmm;
2418  plsc->aspdev = lx / ly;
2419 
2420 // Initialize driver interface
2421 
2422  pldi_ini();
2423 
2424 // Apply compensating factor to original xpmm and ypmm so that
2425 // character aspect ratio is preserved when overall aspect ratio
2426 // is changed. This must appear here in the code because previous
2427 // code in this routine and in routines that it calls must use the original
2428 // values of xpmm and ypmm before the compensating factor is applied.
2429 
2430  plP_gpixmm( &xpmm_loc, &ypmm_loc );
2431  plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
2432 }
2433 
2434 //--------------------------------------------------------------------------
2435 // void plend()
2436 //
2437 // End a plotting session for all open streams.
2438 //--------------------------------------------------------------------------
2439 
2440 void
2441 c_plend( void )
2442 {
2443  PLINT i;
2444 
2445  if ( lib_initialized == 0 )
2446  return;
2447 
2448  for ( i = PL_NSTREAMS - 1; i >= 0; i-- )
2449  {
2450  if ( pls[i] != NULL )
2451  {
2452  plsstrm( i );
2453  c_plend1();
2454  }
2455  }
2456  plfontrel();
2457 #ifdef ENABLE_DYNDRIVERS
2458 // Release the libltdl resources
2459  lt_dlexit();
2460 // Free up memory allocated to the dispatch tables
2461  for ( i = 0; i < npldynamicdevices; i++ )
2462  {
2463  free_mem( loadable_device_list[i].devnam );
2464  free_mem( loadable_device_list[i].description );
2465  free_mem( loadable_device_list[i].drvnam );
2466  free_mem( loadable_device_list[i].tag );
2467  }
2468  free_mem( loadable_device_list );
2469  for ( i = 0; i < nloadabledrivers; i++ )
2470  {
2471  free_mem( loadable_driver_list[i].drvnam );
2472  }
2473  free_mem( loadable_driver_list );
2474  for ( i = nplstaticdevices; i < npldrivers; i++ )
2475  {
2476  free_mem( dispatch_table[i]->pl_MenuStr );
2477  free_mem( dispatch_table[i]->pl_DevName );
2478  free_mem( dispatch_table[i] );
2479  }
2480 #endif
2481  for ( i = 0; i < nplstaticdevices; i++ )
2482  {
2483  free_mem( dispatch_table[i] );
2484  }
2486 
2487  lib_initialized = 0;
2488 }
2489 
2490 //--------------------------------------------------------------------------
2491 // void plend1()
2492 //
2493 // End a plotting session for the current stream only. After the stream is
2494 // ended the memory associated with the stream's PLStream data structure is
2495 // freed (for stream > 0), and the stream counter is set to 0 (the default).
2496 //--------------------------------------------------------------------------
2497 
2498 void
2499 c_plend1( void )
2500 {
2501  if ( plsc->level > 0 )
2502  {
2503  plP_eop();
2504  plP_tidy();
2505  plsc->level = 0;
2506  }
2507  // Move from plP_tidy because FileName may be set even if level == 0
2508  if ( plsc->FileName )
2509  free_mem( plsc->FileName );
2510 
2511 // Free all malloc'ed stream memory
2512 
2513  free_mem( plsc->cmap0 );
2514  free_mem( plsc->cmap1 );
2515  free_mem( plsc->plwindow );
2516  free_mem( plsc->geometry );
2517  free_mem( plsc->dev );
2518  free_mem( plsc->BaseName );
2519  free_mem( plsc->plbuf_buffer );
2520 
2521  if ( plsc->program )
2522  free_mem( plsc->program );
2523  if ( plsc->server_name )
2524  free_mem( plsc->server_name );
2525  if ( plsc->server_host )
2526  free_mem( plsc->server_host );
2527  if ( plsc->server_port )
2528  free_mem( plsc->server_port );
2529  if ( plsc->user )
2530  free_mem( plsc->user );
2531  if ( plsc->plserver )
2532  free_mem( plsc->plserver );
2533  if ( plsc->auto_path )
2534  free_mem( plsc->auto_path );
2535 
2536  if ( plsc->arrow_x )
2537  free_mem( plsc->arrow_x );
2538  if ( plsc->arrow_y )
2539  free_mem( plsc->arrow_y );
2540 
2541  if ( plsc->timefmt )
2542  free_mem( plsc->timefmt );
2543 
2544  // Close qsastime library for this stream that was opened by
2545  // plconfigtime call in plinit.
2546 
2547  closeqsas( &( plsc->qsasconfig ) );
2548 
2549  // Free memory used by the plot metafiles
2550  if ( plsc->mf_infile )
2551  free_mem( plsc->mf_infile );
2552  if ( plsc->mf_outfile )
2553  free_mem( plsc->mf_outfile );
2554 
2555 // Free malloc'ed stream if not in initial stream, else clear it out
2556 
2557  if ( ipls > 0 )
2558  {
2559  free_mem( plsc );
2560  pls[ipls] = NULL;
2561  plsstrm( 0 );
2562  }
2563  else
2564  {
2565  memset( (char *) pls[ipls], 0, sizeof ( PLStream ) );
2566  }
2567 }
2568 
2569 //--------------------------------------------------------------------------
2570 // void plsstrm
2571 //
2572 // Set stream number. If the data structure for a new stream is
2573 // unallocated, we allocate it here.
2574 //--------------------------------------------------------------------------
2575 
2576 void
2578 {
2579  if ( strm < 0 || strm >= PL_NSTREAMS )
2580  {
2581  fprintf( stderr,
2582  "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
2583  (int) strm, PL_NSTREAMS );
2584  }
2585  else
2586  {
2587  ipls = strm;
2588  if ( pls[ipls] == NULL )
2589  {
2590  pls[ipls] = (PLStream *) malloc( (size_t) sizeof ( PLStream ) );
2591  if ( pls[ipls] == NULL )
2592  plexit( "plsstrm: Out of memory." );
2593 
2594  memset( (char *) pls[ipls], 0, sizeof ( PLStream ) );
2595  }
2596  plsc = pls[ipls];
2597  plsc->ipls = ipls;
2598  }
2599 }
2600 
2601 //--------------------------------------------------------------------------
2602 // void plgstrm
2603 //
2604 // Get current stream number.
2605 //--------------------------------------------------------------------------
2606 
2607 void
2608 c_plgstrm( PLINT *p_strm )
2609 {
2610  *p_strm = ipls;
2611 }
2612 
2613 //--------------------------------------------------------------------------
2614 // void plmkstrm
2615 //
2616 // Creates a new stream and makes it the default. Differs from using
2617 // plsstrm(), in that a free stream number is found, and returned.
2618 //
2619 // Unfortunately, I /have/ to start at stream 1 and work upward, since
2620 // stream 0 is preallocated. One of the BIG flaws in the PLplot API is
2621 // that no initial, library-opening call is required. So stream 0 must be
2622 // preallocated, and there is no simple way of determining whether it is
2623 // already in use or not.
2624 //--------------------------------------------------------------------------
2625 
2626 void
2627 c_plmkstrm( PLINT *p_strm )
2628 {
2629  int i;
2630 
2631  for ( i = 1; i < PL_NSTREAMS; i++ )
2632  {
2633  if ( pls[i] == NULL )
2634  break;
2635  }
2636 
2637  if ( i == PL_NSTREAMS )
2638  {
2639  fprintf( stderr, "plmkstrm: Cannot create new stream\n" );
2640  *p_strm = -1;
2641  }
2642  else
2643  {
2644  *p_strm = i;
2645  plsstrm( i );
2646  }
2647  plstrm_init();
2648 }
2649 
2650 //--------------------------------------------------------------------------
2651 // void plstrm_init
2652 //
2653 // Does required startup initialization of a stream. Should be called right
2654 // after creating one (for allocating extra memory, etc). Users shouldn't
2655 // need to call this directly.
2656 //
2657 // This function can be called multiple times for a given stream, in which
2658 // case only the first call produces any effect. For streams >= 1, which
2659 // are created dynamically, this is called by the routine that allocates
2660 // the stream. Stream 0, which is preallocated, is much harder to deal with
2661 // because any of a number of different calls may be the first call to the
2662 // library. This is handled by just calling plstrm_init() from every
2663 // function that might be called first. Sucks, but it should work.
2664 //--------------------------------------------------------------------------
2665 
2666 void
2668 {
2669  if ( !plsc->initialized )
2670  {
2671  plsc->initialized = 1;
2672 
2673  if ( plsc->cmap0 == NULL )
2674  plspal0( "" );
2675 
2676  if ( plsc->cmap1 == NULL )
2677  plspal1( "", TRUE );
2678 
2679  // Set continuous plots to use the full color map 1 range
2680  plsc->cmap1_min = 0.0;
2681  plsc->cmap1_max = 1.0;
2682  }
2683 
2684  plsc->psdoc = NULL;
2685 }
2686 
2687 //--------------------------------------------------------------------------
2688 // pl_cpcolor
2689 //
2690 // Utility to copy one PLColor to another.
2691 //--------------------------------------------------------------------------
2692 
2693 void
2695 {
2696  to->r = from->r;
2697  to->g = from->g;
2698  to->b = from->b;
2699  to->a = from->a;
2700 }
2701 
2702 //--------------------------------------------------------------------------
2703 // void plcpstrm
2704 //
2705 // Copies state parameters from the reference stream to the current stream.
2706 // Tell driver interface to map device coordinates unless flags == 1.
2707 //
2708 // This function is used for making save files of selected plots (e.g.
2709 // from the TK driver). After initializing, you can get a copy of the
2710 // current plot to the specified device by switching to this stream and
2711 // issuing a plcpstrm() and a plreplot(), with calls to plbop() and
2712 // pleop() as appropriate. The plot buffer must have previously been
2713 // enabled (done automatically by some display drivers, such as X).
2714 //--------------------------------------------------------------------------
2715 
2716 void
2717 c_plcpstrm( PLINT iplsr, PLINT flags )
2718 {
2719  int i;
2720  PLStream *plsr;
2721 
2722  plsr = pls[iplsr];
2723  if ( plsr == NULL )
2724  {
2725  fprintf( stderr, "plcpstrm: stream %d not in use\n", (int) iplsr );
2726  return;
2727  }
2728 
2729 // May be debugging
2730 
2731  plsc->debug = plsr->debug;
2732 
2733 // Plot buffer -- need to copy buffer pointer so that plreplot() works
2734 // This also prevents inadvertent writes into the plot buffer
2735  plsc->plbuf_buffer_grow = plsr->plbuf_buffer_grow;
2736  plsc->plbuf_buffer_size = plsr->plbuf_buffer_size;
2737  plsc->plbuf_top = plsr->plbuf_top;
2738  plsc->plbuf_readpos = plsr->plbuf_readpos;
2739  if ( ( plsc->plbuf_buffer = malloc( plsc->plbuf_buffer_size ) ) == NULL )
2740  plexit( "plcpstrm: Error allocating plot buffer." );
2741  memcpy( plsc->plbuf_buffer, plsr->plbuf_buffer, plsr->plbuf_top );
2742 
2743 // Driver interface
2744 // Transformation must be recalculated in current driver coordinates
2745 
2746  if ( plsr->difilt & PLDI_PLT )
2747  plsdiplt( plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax );
2748 
2749  if ( plsr->difilt & PLDI_DEV )
2750  plsdidev( plsr->mar, plsr->aspect, plsr->jx, plsr->jy );
2751 
2752  if ( plsr->difilt & PLDI_ORI )
2753  plsdiori( plsr->diorot );
2754 
2755 // Map device coordinates
2756 
2757  if ( !( flags & 0x01 ) )
2758  {
2759  pldebug( "plcpstrm", "mapping parameters: %d %d %d %d %f %f\n",
2760  plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
2761  plsr->xpmm, plsr->ypmm );
2762  plsdimap( plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
2763  plsr->xpmm, plsr->ypmm );
2764  }
2765 
2766 // current color
2767 
2768  pl_cpcolor( &plsc->curcolor, &plsr->curcolor );
2769 
2770 // cmap 0
2771 
2772  plsc->icol0 = plsr->icol0;
2773  plsc->ncol0 = plsr->ncol0;
2774  if ( plsc->cmap0 != NULL )
2775  free( (void *) plsc->cmap0 );
2776 
2777  if ( ( plsc->cmap0 = (PLColor *) calloc( 1, (size_t) plsc->ncol0 * sizeof ( PLColor ) ) ) == NULL )
2778  {
2779  plexit( "c_plcpstrm: Insufficient memory" );
2780  }
2781 
2782  for ( i = 0; i < plsc->ncol0; i++ )
2783  pl_cpcolor( &plsc->cmap0[i], &plsr->cmap0[i] );
2784 
2785 // cmap 1
2786 
2787  plsc->icol1 = plsr->icol1;
2788  plsc->ncol1 = plsr->ncol1;
2789  plsc->cmap1_min = plsr->cmap1_min;
2790  plsc->cmap1_max = plsr->cmap1_max;
2791  if ( plsc->cmap1 != NULL )
2792  free( (void *) plsc->cmap1 );
2793 
2794  if ( ( plsc->cmap1 = (PLColor *) calloc( 1, (size_t) plsc->ncol1 * sizeof ( PLColor ) ) ) == NULL )
2795  {
2796  plexit( "c_plcpstrm: Insufficient memory" );
2797  }
2798 
2799  for ( i = 0; i < plsc->ncol1; i++ )
2800  pl_cpcolor( &plsc->cmap1[i], &plsr->cmap1[i] );
2801 
2802 // Initialize if it hasn't been done yet.
2803 
2804  if ( plsc->level == 0 )
2805  plinit();
2806 }
2807 
2808 //--------------------------------------------------------------------------
2809 // pllib_devinit()
2810 //
2811 // Does preliminary setup of device driver.
2812 //
2813 // This function (previously plGetDev) used to be what is now shown as
2814 // plSelectDev below. However, the situation is a bit more complicated now in
2815 // the dynloadable drivers era. We now have to:
2816 //
2817 // 1) Make sure the dispatch table is initialized to the union of static
2818 // drivers and available dynamic drivers (done from pllib_init now).
2819 // 2) Allow the user to select the desired device.
2820 // 3) Initialize the dispatch table entries for the selected device, in the
2821 // case that it is a dynloadable driver that has not yet been loaded.
2822 //
2823 // Also made non-static, in order to allow some device calls to be made prior
2824 // to calling plinit(). E.g. plframe needs to tell the X driver to create its
2825 // internal data structure during widget construction time (using the escape
2826 // function), but doesn't call plinit() until the plframe is actually mapped.
2827 //--------------------------------------------------------------------------
2828 
2829 void
2831 {
2832  if ( plsc->dev_initialized )
2833  return;
2834  plsc->dev_initialized = 1;
2835 
2836  plSelectDev();
2837 
2838  plLoadDriver();
2839 
2840 // offset by one since table is zero-based, but input list is not
2841  plsc->dispatch_table = dispatch_table[plsc->device - 1];
2842 }
2843 
2845 {
2846  static int inited = 0;
2847  static int inBuildTree = 0;
2848 
2849  if ( inited == 0 )
2850  {
2851  int len_currdir, len_builddir;
2852  char currdir[PLPLOT_MAX_PATH], *pcurrdir = currdir;
2853  char builddir[PLPLOT_MAX_PATH], *pbuilddir = builddir;
2854 
2855 
2856  if ( getcwd( currdir, PLPLOT_MAX_PATH ) == NULL )
2857  {
2858  pldebug( "plInBuildTree():", "Not enough buffer space" );
2859  }
2860  else
2861  {
2862  // The chdir / getcwd call is to ensure we get the physical
2863  // path without any symlinks
2864  // Ignore error in chdir - build tree may not exist
2865  if ( chdir( BUILD_DIR ) == 0 )
2866  {
2867  if ( getcwd( builddir, PLPLOT_MAX_PATH ) == NULL )
2868  {
2869  pldebug( "plInBuildTree():", "Not enough buffer space" );
2870  }
2871  else
2872  {
2873  len_currdir = strlen( currdir );
2874  len_builddir = strlen( builddir );
2875 #if defined ( _MSC_VER )
2876  // On Windows all parts of the path are case insensitive
2877  // so convert to lower case for the comparison.
2878  for (; *pcurrdir; ++pcurrdir )
2879  *pcurrdir = tolower( *pcurrdir );
2880  for (; *pbuilddir; ++pbuilddir )
2881  *pbuilddir = tolower( *pbuilddir );
2882 #define PLPLOT_PATH_DELIMITER '\\'
2883 #else
2884 #define PLPLOT_PATH_DELIMITER '/'
2885 #endif
2886  // builddir does not have trailing path delimiter
2887  // so the strncmp comparison checks if currdir is
2888  // exactly the builddir or builddir with a string
2889  // appended. So if that test succeeds, then check
2890  // further if the currdir is exactly the build_dir
2891  // or the appended string starts with the path
2892  // delimiter, i.e., whether currdir is the builddir or
2893  // a subdirectory of that directory.
2894  if ( strncmp( builddir, currdir, len_builddir ) == 0 &&
2895  ( len_currdir == len_builddir || currdir[len_builddir] == PLPLOT_PATH_DELIMITER ) )
2896  {
2897  inBuildTree = 1;
2898  }
2899  }
2900  if ( chdir( currdir ) != 0 )
2901  pldebug( "plInBuildTree():", "Unable to chdir to current directory" );
2902  }
2903  }
2904  inited = 1;
2905  }
2906  return inBuildTree;
2907 }
2908 
2909 #ifdef ENABLE_DYNDRIVERS
2910 
2911 const char*
2912 plGetDrvDir()
2913 {
2914  const char* drvdir;
2915 
2916 // Get drivers directory in PLPLOT_DRV_DIR or DRV_DIR,
2917 // on this order
2918 //
2919 
2920  if ( plInBuildTree() == 1 )
2921  {
2922  drvdir = BUILD_DIR "/drivers";
2923  pldebug( "plGetDrvDir", "Using %s as the driver directory.\n", drvdir );
2924  }
2925  else
2926  {
2927  pldebug( "plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n" );
2928  drvdir = getenv( "PLPLOT_DRV_DIR" );
2929 
2930  if ( drvdir == NULL )
2931  {
2932  pldebug( "plGetDrvDir",
2933  "Will use drivers dir: " DRV_DIR "\n" );
2934  drvdir = DRV_DIR;
2935  }
2936  }
2937 
2938  return drvdir;
2939 }
2940 
2941 #endif
2942 
2943 
2944 //--------------------------------------------------------------------------
2945 // void plInitDispatchTable()
2946 //
2947 // ...
2948 //--------------------------------------------------------------------------
2949 
2950 static int plDispatchSequencer( const void *p1, const void *p2 )
2951 {
2952  const PLDispatchTable* t1 = *(const PLDispatchTable * const *) p1;
2953  const PLDispatchTable* t2 = *(const PLDispatchTable * const *) p2;
2954 
2955 // printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n",
2956 // t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq );
2957 
2958  return t1->pl_seq - t2->pl_seq;
2959 }
2960 
2961 static void
2963 {
2964  int n;
2965 
2966 #ifdef ENABLE_DYNDRIVERS
2967  char buf[BUFFER2_SIZE];
2968  const char * drvdir;
2969  char *devnam, *devdesc, *devtype, *driver, *tag, *seqstr;
2970  int seq;
2971  int i, j, driver_found, done = 0;
2972  FILE *fp_drvdb = NULL;
2973  DIR * dp_drvdir = NULL;
2974  struct dirent* entry;
2975  // lt_dlhandle dlhand;
2976 
2977  // Make sure driver counts are zeroed
2978  npldynamicdevices = 0;
2979  nloadabledrivers = 0;
2980 
2981 // Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings
2982 // will be stored
2983  fp_drvdb = pl_create_tempfile( NULL );
2984  if ( fp_drvdb == NULL )
2985  {
2986  plabort( "plInitDispatchTable: Could not open temporary file" );
2987  return;
2988  }
2989 
2990 // Open the drivers directory
2991  drvdir = plGetDrvDir();
2992  dp_drvdir = opendir( drvdir );
2993  if ( dp_drvdir == NULL )
2994  {
2995  fclose( fp_drvdb );
2996  plabort( "plInitDispatchTable: Could not open drivers directory" );
2997  return;
2998  }
2999 
3000 // Loop over each entry in the drivers directory
3001 
3002  pldebug( "plInitDispatchTable", "Scanning dyndrivers dir\n" );
3003  while ( ( entry = readdir( dp_drvdir ) ) != NULL )
3004  {
3005  char * name = entry->d_name;
3006  // Suffix .driver_info has a length of 12 letters.
3007  size_t len = strlen( name ) - 12;
3008 
3009  pldebug( "plInitDispatchTable",
3010  "Consider file %s\n", name );
3011 
3012 // Only consider entries that have the ".driver_info" suffix
3013  if ( ( len > 0 ) && ( strcmp( name + len, ".driver_info" ) == 0 ) )
3014  {
3015  char path[PLPLOT_MAX_PATH];
3016  FILE * fd;
3017 
3018 // Open the driver's info file
3019  snprintf( path, PLPLOT_MAX_PATH, "%s/%s", drvdir, name );
3020  fd = fopen( path, "r" );
3021  if ( fd == NULL )
3022  {
3023  closedir( dp_drvdir );
3024  fclose( fp_drvdb );
3025  snprintf( buf, BUFFER2_SIZE,
3026  "plInitDispatchTable: Could not open driver info file %s\n",
3027  name );
3028  plabort( buf );
3029  return;
3030  }
3031 
3032 // Each line in the <driver>.driver_info file corresponds to a specific device.
3033 // Write it to the drivers db file and take care of leading newline
3034 // character
3035 
3036  pldebug( "plInitDispatchTable",
3037  "Opened driver info file %s\n", name );
3038  while ( fgets( buf, BUFFER2_SIZE, fd ) != NULL )
3039  {
3040  fprintf( fp_drvdb, "%s", buf );
3041  if ( buf [strlen( buf ) - 1] != '\n' )
3042  fprintf( fp_drvdb, "\n" );
3044  }
3045  fclose( fd );
3046  }
3047  }
3048 
3049 // Make sure that the temporary file containing the drivers database
3050 // is ready to read and close the directory handle
3051  fflush( fp_drvdb );
3052  closedir( dp_drvdir );
3053 
3054 #endif
3055 
3056 // Allocate space for the dispatch table.
3057  if ( ( dispatch_table = (PLDispatchTable **)
3058  malloc( (size_t) ( nplstaticdevices + npldynamicdevices ) * sizeof ( PLDispatchTable * ) ) ) == NULL )
3059  {
3060 #ifdef ENABLE_DYNDRIVERS
3061  fclose( fp_drvdb );
3062 #endif
3063  plexit( "plInitDispatchTable: Insufficient memory" );
3064  }
3065 
3066 // Initialize the dispatch table entries for the static devices by calling
3067 // the dispatch table initialization function for each static device. This
3068 // is the same function that would be called at load time for dynamic
3069 // drivers.
3070 
3071  for ( n = 0; n < nplstaticdevices; n++ )
3072  {
3073  if ( ( dispatch_table[n] = (PLDispatchTable *) malloc( sizeof ( PLDispatchTable ) ) ) == NULL )
3074  {
3075 #ifdef ENABLE_DYNDRIVERS
3076  fclose( fp_drvdb );
3077 #endif
3078  plexit( "plInitDispatchTable: Insufficient memory" );
3079  }
3080 
3082  }
3084 
3085 #ifdef ENABLE_DYNDRIVERS
3086 
3087 // Allocate space for the device and driver specs. We may not use all of
3088 // these driver descriptors, but we obviously won't need more drivers than
3089 // devices...
3090  if ( ( ( loadable_device_list = malloc( (size_t) npldynamicdevices * sizeof ( PLLoadableDevice ) ) ) == NULL ) ||
3091  ( ( loadable_driver_list = malloc( (size_t) npldynamicdevices * sizeof ( PLLoadableDriver ) ) ) == NULL ) )
3092  {
3093  fclose( fp_drvdb );
3094  plexit( "plInitDispatchTable: Insufficient memory" );
3095  }
3096 
3097  rewind( fp_drvdb );
3098 
3099  i = 0;
3100  done = !( i < npldynamicdevices );
3101  while ( !done )
3102  {
3103  char *p = fgets( buf, BUFFER2_SIZE, fp_drvdb );
3104 
3105  if ( p == 0 )
3106  {
3107  done = 1;
3108  continue;
3109  }
3110 
3111  devnam = strtok( buf, ":" );
3112  devdesc = strtok( 0, ":" );
3113  devtype = strtok( 0, ":" );
3114  driver = strtok( 0, ":" );
3115  seqstr = strtok( 0, ":" );
3116  tag = strtok( 0, "\n" );
3117 
3118  if ( devnam == NULL || devdesc == NULL || devtype == NULL || driver == NULL ||
3119  seqstr == NULL || tag == NULL )
3120  {
3121  continue; // Ill-formatted line, most probably not a valid driver information file
3122  }
3123 
3124  seq = atoi( seqstr );
3125 
3126  n = npldrivers++;
3127 
3128  if ( ( dispatch_table[n] = malloc( sizeof ( PLDispatchTable ) ) ) == NULL )
3129  {
3130  fclose( fp_drvdb );
3131  plexit( "plInitDispatchTable: Insufficient memory" );
3132  }
3133 
3134  // Fill in the dispatch table entries.
3135  dispatch_table[n]->pl_MenuStr = plstrdup( devdesc );
3136  dispatch_table[n]->pl_DevName = plstrdup( devnam );
3137  dispatch_table[n]->pl_type = atoi( devtype );
3138  dispatch_table[n]->pl_seq = seq;
3139  dispatch_table[n]->pl_init = 0;
3140  dispatch_table[n]->pl_line = 0;
3141  dispatch_table[n]->pl_polyline = 0;
3142  dispatch_table[n]->pl_eop = 0;
3143  dispatch_table[n]->pl_bop = 0;
3144  dispatch_table[n]->pl_tidy = 0;
3145  dispatch_table[n]->pl_state = 0;
3146  dispatch_table[n]->pl_esc = 0;
3147 
3148  // Add a record to the loadable device list
3149  loadable_device_list[i].devnam = plstrdup( devnam );
3150  loadable_device_list[i].description = plstrdup( devdesc );
3151  loadable_device_list[i].drvnam = plstrdup( driver );
3152  loadable_device_list[i].tag = plstrdup( tag );
3153 
3154  // Now see if this driver has been seen before. If not, add a driver
3155  // entry for it.
3156  driver_found = 0;
3157  for ( j = 0; j < nloadabledrivers; j++ )
3158  if ( strcmp( driver, loadable_driver_list[j].drvnam ) == 0 )
3159  {
3160  driver_found = 1;
3161  break;
3162  }
3163 
3164  if ( !driver_found )
3165  {
3166  loadable_driver_list[nloadabledrivers].drvnam = plstrdup( driver );
3167  loadable_driver_list[nloadabledrivers].dlhand = 0;
3168  nloadabledrivers++;
3169  }
3170 
3171  loadable_device_list[i].drvidx = j;
3172 
3173  // Get ready for next loadable device spec
3174  i++;
3175  }
3176 
3177 // RML: close fp_drvdb
3178  fclose( fp_drvdb );
3179 
3180 #endif
3181 
3182  if ( npldrivers == 0 )
3183  {
3184  npldynamicdevices = 0;
3185  plexit( "No device drivers found - please check the environment variable PLPLOT_DRV_DIR" );
3186  }
3187 
3188 // Finally, we need to sort the list into presentation order, based on the
3189 // sequence number in the dispatch ttable entries.
3190 
3191  qsort( dispatch_table, (size_t) npldrivers, sizeof ( PLDispatchTable* ),
3193 }
3194 
3195 //--------------------------------------------------------------------------
3196 // void plSelectDev()
3197 //
3198 // If the user has not already specified the output device, or the
3199 // one specified is either: (a) not available, (b) "?", or (c) NULL, the
3200 // user is prompted for it.
3201 //
3202 // Prompting quits after 10 unsuccessful tries in case the user has
3203 // run the program in the background with insufficient input.
3204 //--------------------------------------------------------------------------
3205 
3206 static void
3208 {
3209  int dev, i, count;
3210  size_t length;
3211  char response[80];
3212  char * devname_env;
3213 
3214 // If device name is not already specified, try to get it from environment
3215 
3216  if ( plsc->DevName[0] == '\0' )
3217  {
3218  devname_env = getenv( "PLPLOT_DEV" );
3219  if ( devname_env )
3220  {
3221  strncpy( plsc->DevName, devname_env, sizeof ( plsc->DevName ) - 1 );
3222  plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0';
3223  }
3224  }
3225 
3226 // Device name already specified. See if it is valid.
3227 
3228  if ( *( plsc->DevName ) != '\0' && *( plsc->DevName ) != '?' )
3229  {
3230  length = strlen( plsc->DevName );
3231  for ( i = 0; i < npldrivers; i++ )
3232  {
3233  if ( ( *plsc->DevName == *dispatch_table[i]->pl_DevName ) &&
3234  ( strncmp( plsc->DevName,
3235  dispatch_table[i]->pl_DevName, length ) == 0 ) )
3236  break;
3237  }
3238  if ( i < npldrivers )
3239  {
3240  plsc->device = i + 1;
3241  return;
3242  }
3243  else
3244  {
3245  fprintf( stderr, "Requested device %s not available\n",
3246  plsc->DevName );
3247  }
3248  }
3249 
3250  dev = 0;
3251  count = 0;
3252 
3253  if ( npldrivers == 1 )
3254  dev = 1;
3255 
3256 // User hasn't specified it correctly yet, so we prompt
3257 
3258  while ( dev < 1 || dev > npldrivers )
3259  {
3260  fprintf( stdout, "\nPlotting Options:\n" );
3261  for ( i = 0; i < npldrivers; i++ )
3262  {
3263  fprintf( stdout, " <%2d> %-10s %s\n", i + 1,
3264  dispatch_table[i]->pl_DevName,
3265  dispatch_table[i]->pl_MenuStr );
3266  }
3267  if ( ipls == 0 )
3268  fprintf( stdout, "\nEnter device number or keyword: " );
3269  else
3270  fprintf( stdout, "\nEnter device number or keyword (stream %d): ",
3271  (int) ipls );
3272 
3273  plio_fgets( response, sizeof ( response ), stdin );
3274 
3275  // First check to see if device keyword was entered.
3276  // Final "\n" in response messes things up, so ignore it.
3277 
3278  length = strlen( response );
3279  if ( *( response - 1 + length ) == '\n' )
3280  length--;
3281 
3282  for ( i = 0; i < npldrivers; i++ )
3283  {
3284  if ( !strncmp( response, dispatch_table[i]->pl_DevName,
3285  (unsigned int) length ) )
3286  break;
3287  }
3288  if ( i < npldrivers )
3289  {
3290  dev = i + 1;
3291  }
3292  else
3293  {
3294  if ( ( dev = atoi( response ) ) < 1 )
3295  {
3296  fprintf( stdout, "\nInvalid device: %s", response );
3297  dev = 0;
3298  }
3299  }
3300  if ( count++ > 10 )
3301  plexit( "plSelectDev: Too many tries." );
3302  }
3303  plsc->device = dev;
3304  strcpy( plsc->DevName, dispatch_table[dev - 1]->pl_DevName );
3305 }
3306 
3307 //--------------------------------------------------------------------------
3308 // void plLoadDriver()
3309 //
3310 // Make sure the selected driver is loaded. Static drivers are already
3311 // loaded, but if the user selected a dynamically loadable driver, we may
3312 // have to take care of that now.
3313 //--------------------------------------------------------------------------
3314 
3315 static void
3317 {
3318 #ifdef ENABLE_DYNDRIVERS
3319  int i, drvidx;
3320  char sym[BUFFER_SIZE];
3321  char *tag;
3322 
3323  int n = plsc->device - 1;
3324  PLDispatchTable *dev = dispatch_table[n];
3325  PLLoadableDriver *driver = 0;
3326 
3327 // If the dispatch table is already filled in, then either the device was
3328 // linked in statically, or else perhaps it was already loaded. In either
3329 // case, we have nothing left to do.
3330  if ( dev->pl_init )
3331  return;
3332 
3333  pldebug( "plLoadDriver", "Device not loaded!\n" );
3334 
3335 // Now search through the list of loadable devices, looking for the record
3336 // that corresponds to the requested device.
3337  for ( i = 0; i < npldynamicdevices; i++ )
3338  if ( strcmp( dev->pl_DevName, loadable_device_list[i].devnam ) == 0 )
3339  break;
3340 
3341 // If we couldn't find such a record, then there is some sort of internal
3342 // logic flaw since plSelectDev is supposed to only select a valid device.
3343 //
3344  if ( i == npldynamicdevices )
3345  {
3346  fprintf( stderr, "No such device: %s.\n", dev->pl_DevName );
3347  plexit( "plLoadDriver detected device logic screwup" );
3348  }
3349 
3350 // Note the device tag, and the driver index. Note that a given driver could
3351 // supply multiple devices, each with a unique tag to distinguish the driver
3352 // entry points for the different supported devices.
3353  tag = loadable_device_list[i].tag;
3354  drvidx = loadable_device_list[i].drvidx;
3355 
3356  pldebug( "plLoadDriver", "tag=%s, drvidx=%d\n", tag, drvidx );
3357 
3358  driver = &loadable_driver_list[drvidx];
3359 
3360 // Load the driver if it hasn't been loaded yet.
3361  if ( !driver->dlhand )
3362  {
3363  char drvspec[ DRVSPEC_SIZE ];
3364 #if defined ( LTDL_WIN32 ) || defined ( __CYGWIN__ )
3365  snprintf( drvspec, DRVSPEC_SIZE, "%s", driver->drvnam );
3366 #else
3367  snprintf( drvspec, DRVSPEC_SIZE, "%s/%s", plGetDrvDir(), driver->drvnam );
3368 #endif // LTDL_WIN32
3369 
3370  pldebug( "plLoadDriver", "Trying to load %s on %s\n",
3371  driver->drvnam, drvspec );
3372 
3373  driver->dlhand = lt_dlopenext( drvspec );
3374 
3375  // A few of our drivers do not depend on other libraries. So
3376  // allow them to be completely removed by plend to give clean
3377  // valgrind results. However, the (large) remainder of our
3378  // drivers do depend on other libraries so mark them resident
3379  // to prevent problems with atexit handlers / library
3380  // reinitialisation such as those seen with qt and cairo
3381  // drivers.
3382  if ( !( strcmp( driver->drvnam, "mem" ) == 0 ||
3383  strcmp( driver->drvnam, "null" ) == 0 ||
3384  strcmp( driver->drvnam, "plmeta" ) == 0 ||
3385  strcmp( driver->drvnam, "ps" ) == 0 ||
3386  strcmp( driver->drvnam, "svg" ) == 0 ||
3387  strcmp( driver->drvnam, "xfig" ) == 0 ) )
3388  lt_dlmakeresident( driver->dlhand );
3389  }
3390 
3391 // If it still isn't loaded, then we're doomed.
3392  if ( !driver->dlhand )
3393  {
3394  pldebug( "plLoadDriver", "lt_dlopenext failed because of "
3395  "the following reason:\n%s\n", lt_dlerror() );
3396  fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam );
3397  plexit( "Unable to load driver" );
3398  }
3399 
3400 // Now we are ready to ask the driver's device dispatch init function to
3401 // initialize the entries in the dispatch table.
3402 
3403  snprintf( sym, BUFFER_SIZE, "plD_dispatch_init_%s", tag );
3404  {
3405  PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym );
3406  if ( !dispatch_init )
3407  {
3408  fprintf( stderr,
3409  "Unable to locate dispatch table initialization function for driver: %s.\n",
3410  driver->drvnam );
3411  return;
3412  }
3413 
3414  ( *dispatch_init )( dev );
3415  }
3416 #endif
3417 }
3418 
3419 //--------------------------------------------------------------------------
3420 // void plfontld()
3421 //
3422 // Load specified font set.
3423 //--------------------------------------------------------------------------
3424 
3425 void
3427 {
3428  if ( ifont != 0 )
3429  ifont = 1;
3430 
3431  if ( plsc->level > 0 )
3432  plfntld( ifont );
3433  else
3434  initfont = ifont;
3435 }
3436 
3437 //--------------------------------------------------------------------------
3438 // void plreplot()
3439 //
3440 // Replays contents of plot buffer to current device/file.
3441 //--------------------------------------------------------------------------
3442 
3443 void
3444 c_plreplot( void )
3445 {
3446  if ( plsc->plbuf_buffer != NULL )
3447  {
3448  plRemakePlot( plsc );
3449  }
3450  else
3451  {
3452  plwarn( "plreplot: plot buffer not available" );
3453  }
3454 }
3455 
3456 //--------------------------------------------------------------------------
3457 // void plgFileDevs()
3458 //
3459 // Returns a list of file-oriented device names and their menu strings,
3460 // for use in a graphical interface. The caller must allocate enough
3461 // space for (*p_menustr) and (*p_devname) to hold a pointer for each
3462 // device -- 20 or so is plenty. E.g. char *menustr[20]. The size of
3463 // these arrays should be passed in *p_ndev, which, on exit, holds the
3464 // number of devices actually present.
3465 //--------------------------------------------------------------------------
3466 
3467 void
3468 plgFileDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev )
3469 {
3470  plgdevlst( *p_menustr, *p_devname, p_ndev, 0 );
3471 }
3472 
3473 //--------------------------------------------------------------------------
3474 // void plgDevs()
3475 //
3476 // Like plgFileDevs(), but returns names and menu strings for all devices.
3477 //--------------------------------------------------------------------------
3478 
3479 void
3480 plgDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev )
3481 {
3482  plgdevlst( *p_menustr, *p_devname, p_ndev, -1 );
3483 }
3484 
3485 static void
3486 plgdevlst( const char **p_menustr, const char **p_devname, int *p_ndev, int type )
3487 {
3488  int i, j;
3489 
3490  pllib_init();
3491 
3492  for ( i = j = 0; i < npldrivers; i++ )
3493  {
3494  if ( type < 0 || dispatch_table[i]->pl_type == type )
3495  {
3496  p_menustr[j] = dispatch_table[i]->pl_MenuStr;
3497  p_devname[j] = dispatch_table[i]->pl_DevName;
3498  if ( ++j + 1 >= *p_ndev )
3499  {
3500  plwarn( "plgdevlst: too many devices" );
3501  break;
3502  }
3503  }
3504  }
3505  p_menustr[j] = NULL;
3506  p_devname[j] = NULL;
3507  *p_ndev = j;
3508 }
3509 
3510 //--------------------------------------------------------------------------
3511 // Various external access routines.
3512 //--------------------------------------------------------------------------
3513 
3514 // Get output device parameters.
3515 
3516 void
3517 c_plgpage( PLFLT *p_xp, PLFLT *p_yp,
3518  PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff )
3519 {
3520  *p_xp = plsc->xdpi;
3521  *p_yp = plsc->ydpi;
3522  *p_xleng = plsc->xlength;
3523  *p_yleng = plsc->ylength;
3524  *p_xoff = plsc->xoffset;
3525  *p_yoff = plsc->yoffset;
3526 }
3527 
3528 // Set output device parameters. Usually ignored by the driver.
3529 
3530 void
3531 c_plspage( PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff )
3532 {
3533  if ( plsc->level > 0 )
3534  plwarn( "calling plspage() after plinit() may give unpredictable results" );
3535 
3536  if ( xp )
3537  plsc->xdpi = xp;
3538  if ( yp )
3539  plsc->ydpi = yp;
3540 
3541  if ( xleng )
3542  plsc->xlength = xleng;
3543  if ( yleng )
3544  plsc->ylength = yleng;
3545 
3546  if ( xoff )
3547  plsc->xoffset = xoff;
3548  if ( yoff )
3549  plsc->yoffset = yoff;
3550 
3551  plsc->pageset = 1;
3552 }
3553 
3554 // Set the number of subwindows in x and y
3555 
3556 void
3558 {
3559  if ( nx > 0 )
3560  plsc->nsubx = nx;
3561  if ( ny > 0 )
3562  plsc->nsuby = ny;
3563 
3564 // Force a page advance
3565 
3566  if ( plsc->level > 0 )
3567  {
3568  plP_subpInit();
3569 //AWI plP_eop();
3570 // plP_bop();
3571  }
3572 }
3573 
3574 // Set the device (keyword) name
3575 
3576 void
3577 c_plsdev( const char *devname )
3578 {
3579  if ( plsc->level > 0 )
3580  {
3581  plwarn( "plsdev: Must be called before plinit." );
3582  return;
3583  }
3584  if ( devname != NULL )
3585  {
3586  strncpy( plsc->DevName, devname, sizeof ( plsc->DevName ) - 1 );
3587  plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0';
3588  }
3589 }
3590 
3591 // Get the current device (keyword) name
3592 // Note: you MUST have allocated space for this (80 characters is safe)
3593 
3594 void
3595 c_plgdev( char *p_dev )
3596 {
3597  strcpy( p_dev, plsc->DevName );
3598 }
3599 
3600 // Set the memory area to be plotted (with the 'mem' driver) as the 'dev'
3601 // member of the stream structure. Also set the number
3602 // of pixels in the memory passed in in 'plotmem'.
3603 // Plotmem is a block of memory maxy by maxx by 3 bytes long, say:
3604 // 480 x 640 x 3 (Y, X, RGB)
3605 //
3606 // This memory will be freed by the user!
3607 //
3608 
3609 void
3610 c_plsmem( PLINT maxx, PLINT maxy, void *plotmem )
3611 {
3612  plsc->dev = plotmem;
3613  plsc->dev_mem_alpha = 0;
3614  plP_setphy( 0, maxx, 0, maxy );
3615 }
3616 
3617 // Same as plsmem, but the buffer is (Y, X, RGBA)
3618 
3619 void
3620 c_plsmema( PLINT maxx, PLINT maxy, void *plotmem )
3621 {
3622  plsc->dev = plotmem;
3623  plsc->dev_mem_alpha = 1;
3624  plP_setphy( 0, maxx, 0, maxy );
3625 }
3626 
3627 // Get the current stream pointer
3628 
3629 void
3630 plgpls( PLStream **p_pls )
3631 {
3632  *p_pls = plsc;
3633 }
3634 
3635 // Get the (current) run level.
3636 // Valid settings are:
3637 // 0 uninitialized
3638 // 1 initialized
3639 // 2 viewport defined
3640 // 3 world coords defined
3641 //
3642 
3643 void
3644 c_plglevel( PLINT *p_level )
3645 {
3646  *p_level = plsc->level;
3647 }
3648 
3649 // Set the function pointer for the keyboard event handler
3650 
3651 void
3652 plsKeyEH( void ( *KeyEH )( PLGraphicsIn *, void *, int * ),
3653  void *KeyEH_data )
3654 {
3655  plsc->KeyEH = KeyEH;
3656  plsc->KeyEH_data = KeyEH_data;
3657 }
3658 
3659 // Set the function pointer for the (mouse) button event handler
3660 
3661 void
3662 plsButtonEH( void ( *ButtonEH )( PLGraphicsIn *, void *, int * ),
3663  void *ButtonEH_data )
3664 {
3665  plsc->ButtonEH = ButtonEH;
3666  plsc->ButtonEH_data = ButtonEH_data;
3667 }
3668 
3669 // Sets an optional user bop handler.
3670 
3671 void
3672 plsbopH( void ( *handler )( void *, int * ), void *handler_data )
3673 {
3674  plsc->bop_handler = handler;
3675  plsc->bop_data = handler_data;
3676 }
3677 
3678 // Sets an optional user eop handler.
3679 
3680 void
3681 plseopH( void ( *handler )( void *, int * ), void *handler_data )
3682 {
3683  plsc->eop_handler = handler;
3684  plsc->eop_data = handler_data;
3685 }
3686 
3687 // Set the variables to be used for storing error info
3688 
3689 void
3690 plsError( PLINT *errcode, char *errmsg )
3691 {
3692  if ( errcode != NULL )
3693  plsc->errcode = errcode;
3694 
3695  if ( errmsg != NULL )
3696  plsc->errmsg = errmsg;
3697 }
3698 
3699 // Set orientation. Must be done before calling plinit.
3700 
3701 void
3703 {
3704  plsdiori( (PLFLT) ori );
3705 }
3706 
3707 //
3708 // Set pen width. Can be done any time, but before calling plinit is best
3709 // since otherwise it may be volatile (i.e. reset on next page advance).
3710 // If width < 0 or is unchanged by the call, nothing is done.
3711 //
3712 
3713 void
3715 {
3716  if ( width != plsc->width && width >= 0. )
3717  {
3718  plsc->width = width;
3719 
3720  if ( plsc->level > 0 )
3721  {
3722  if ( !plsc->widthlock )
3724  }
3725  }
3726 }
3727 
3728 // Set the output file pointer
3729 
3730 void
3731 plgfile( FILE **p_file )
3732 {
3733  *p_file = plsc->OutFile;
3734 }
3735 
3736 // Get the output file pointer
3737 
3738 void
3739 plsfile( FILE *file )
3740 {
3741  plsc->OutFile = file;
3742 }
3743 
3744 // Get the (current) output file name. Must be preallocated to >=80 bytes
3745 // Beyond that, I truncate it. You have been warned.
3746 
3747 void
3748 c_plgfnam( char *fnam )
3749 {
3750  if ( fnam == NULL )
3751  {
3752  plabort( "filename string must be preallocated to >=80 bytes" );
3753  return;
3754  }
3755 
3756  *fnam = '\0';
3757  if ( plsc->FileName != NULL )
3758  {
3759  strncpy( fnam, plsc->FileName, 79 );
3760  fnam[79] = '\0';
3761  }
3762 }
3763 
3764 // Set the output file name.
3765 
3766 void
3767 c_plsfnam( const char *fnam )
3768 {
3769  plP_sfnam( plsc, fnam );
3770 }
3771 
3772 // Set the pointer to the data used in driver initialisation
3773 
3774 // N.B. Currently used only by the wxwidgets device driver and
3775 // associated binding. This function might be used for other device drivers
3776 // later on whether written in c++ or c. But this function is not part of the
3777 // common API and should not be propagated to any binding other than
3778 // c++.
3779 
3780 void
3782 {
3783  plsc->dev_data = data;
3784 }
3785 
3786 // Set the pause (on end-of-page) status
3787 
3788 void
3790 {
3791  plsc->nopause = !p;
3792 }
3793 
3794 // Set the floating point precision (in number of places) in numeric labels.
3795 
3796 void
3797 c_plprec( PLINT setp, PLINT prec )
3798 {
3799  plsc->setpre = setp;
3800  plsc->precis = prec;
3801 }
3802 
3803 // Get the floating point precision (in number of places) in numeric labels.
3804 
3805 void
3806 plP_gprec( PLINT *p_setp, PLINT *p_prec )
3807 {
3808  *p_setp = plsc->setpre;
3809  *p_prec = plsc->precis;
3810 }
3811 
3812 const char *
3814 {
3815  return (const char *) plsc->timefmt;
3816 }
3817 
3818 //
3819 // Set the escape character for text strings.
3820 // From C you can pass as a character, from Fortran it needs to be the decimal
3821 // ASCII value. Only selected characters are allowed to prevent the user from
3822 // shooting himself in the foot (a '\' isn't allowed since it conflicts with
3823 // C's use of backslash as a character escape).
3824 //
3825 
3826 void
3827 c_plsesc( char esc )
3828 {
3829  switch ( esc )
3830  {
3831  case '!': // ASCII 33
3832  case '#': // ASCII 35
3833  case '$': // ASCII 36
3834  case '%': // ASCII 37
3835  case '&': // ASCII 38
3836  case '*': // ASCII 42
3837  case '@': // ASCII 64
3838  case '^': // ASCII 94
3839  case '~': // ASCII 126
3840  plsc->esc = esc;
3841  break;
3842 
3843  default:
3844  plwarn( "plsesc: Invalid escape character, ignoring." );
3845  }
3846 }
3847 
3848 // Get the escape character for text strings.
3849 
3850 void
3851 plgesc( char *p_esc )
3852 {
3853  if ( plsc->esc == '\0' )
3854  plsc->esc = '#';
3855 
3856  *p_esc = plsc->esc;
3857 }
3858 
3859 // Set the FCI (font characterization integer) for unicode-enabled device
3860 // drivers.
3861 //
3862 void
3864 {
3865  // Always mark FCI as such.
3866  plsc->fci = fci | PL_FCI_MARK;
3867 }
3868 
3869 // Get the FCI (font characterization integer) for unicode-enabled device
3870 // drivers.
3871 //
3872 void
3874 {
3875  // Always mark FCI as such.
3876  *p_fci = plsc->fci | PL_FCI_MARK;
3877 }
3878 // Store hex digit value shifted to the left by hexdigit hexadecimal digits
3879 // into pre-existing FCI.
3880 //
3881 void
3882 plP_hex2fci( unsigned char hexdigit, unsigned char hexpower, PLUNICODE *pfci )
3883 {
3884  PLUNICODE mask;
3885  hexpower = hexpower & PL_FCI_HEXPOWER_MASK;
3886  mask = ~( ( (PLUNICODE) PL_FCI_HEXDIGIT_MASK ) << ( (PLUNICODE) 4 * hexpower ) );
3887  *pfci = *pfci & mask;
3888  mask = ( ( (PLUNICODE) ( hexdigit & PL_FCI_HEXDIGIT_MASK ) ) << ( 4 * hexpower ) );
3889  *pfci = *pfci | mask;
3890 }
3891 
3892 // Retrieve hex digit value from FCI that is masked out and shifted to the
3893 // right by hexpower hexadecimal digits.
3894 void
3895 plP_fci2hex( PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower )
3896 {
3897  PLUNICODE mask;
3898  hexpower = hexpower & PL_FCI_HEXPOWER_MASK;
3899  mask = ( ( (PLUNICODE) PL_FCI_HEXPOWER_MASK ) << ( (PLUNICODE) ( 4 * hexpower ) ) );
3900  *phexdigit = (unsigned char) ( ( fci & mask ) >>
3901  ( (PLUNICODE) ( 4 * hexpower ) ) );
3902 }
3903 
3904 // Get the current library version number
3905 // Note: you MUST have allocated space for this (80 characters is safe)
3906 void
3907 c_plgver( char *p_ver )
3908 {
3909  strcpy( p_ver, PLPLOT_VERSION );
3910 }
3911 
3912 // Set inferior X window
3913 
3914 void
3915 plsxwin( PLINT window_id )
3916 {
3917  plsc->window_id = window_id;
3918 }
3919 
3920 //--------------------------------------------------------------------------
3921 // These set/get information for family files, and may be called prior
3922 // to plinit to set up the necessary parameters. Arguments:
3923 //
3924 // fam familying flag (boolean)
3925 // num member number
3926 // bmax maximum member size
3927 //--------------------------------------------------------------------------
3928 
3929 // Get family file parameters
3930 
3931 void
3932 c_plgfam( PLINT *p_fam, PLINT *p_num, PLINT *p_bmax )
3933 {
3934  *p_fam = plsc->family;
3935  *p_num = plsc->member;
3936  *p_bmax = plsc->bytemax;
3937 }
3938 
3939 // Set family file parameters
3940 
3941 void
3942 c_plsfam( PLINT fam, PLINT num, PLINT bmax )
3943 {
3944  if ( plsc->level > 0 )
3945  plwarn( "plsfam: Must be called before plinit." );
3946 
3947  if ( fam >= 0 )
3948  plsc->family = fam;
3949  if ( num >= 0 )
3950  plsc->member = num;
3951  if ( bmax >= 0 )
3952  plsc->bytemax = bmax;
3953 }
3954 
3955 // Advance to the next family file on the next new page
3956 
3957 void
3958 c_plfamadv( void )
3959 {
3960  plsc->famadv = 1;
3961 }
3962 
3963 //--------------------------------------------------------------------------
3964 // Interface routines for axis labling parameters.
3965 // See pldtik.c for more info.
3966 //--------------------------------------------------------------------------
3967 
3968 // Get x axis labeling parameters
3969 
3970 void
3971 c_plgxax( PLINT *p_digmax, PLINT *p_digits )
3972 {
3973  *p_digmax = plsc->xdigmax;
3974  *p_digits = plsc->xdigits;
3975 }
3976 
3977 // Set x axis labeling parameters
3978 
3979 void
3980 c_plsxax( PLINT digmax, PLINT digits )
3981 {
3982  plsc->xdigmax = digmax;
3983  plsc->xdigits = digits;
3984 }
3985 
3986 // Get y axis labeling parameters
3987 
3988 void
3989 c_plgyax( PLINT *p_digmax, PLINT *p_digits )
3990 {
3991  *p_digmax = plsc->ydigmax;
3992  *p_digits = plsc->ydigits;
3993 }
3994 
3995 // Set y axis labeling parameters
3996 
3997 void
3998 c_plsyax( PLINT digmax, PLINT digits )
3999 {
4000  plsc->ydigmax = digmax;
4001  plsc->ydigits = digits;
4002 }
4003 
4004 // Get z axis labeling parameters
4005 
4006 void
4007 c_plgzax( PLINT *p_digmax, PLINT *p_digits )
4008 {
4009  *p_digmax = plsc->zdigmax;
4010  *p_digits = plsc->zdigits;
4011 }
4012 
4013 // Set z axis labeling parameters
4014 
4015 void
4016 c_plszax( PLINT digmax, PLINT digits )
4017 {
4018  plsc->zdigmax = digmax;
4019  plsc->zdigits = digits;
4020 }
4021 
4022 // Get character default height and current (scaled) height
4023 
4024 void
4025 c_plgchr( PLFLT *p_def, PLFLT *p_ht )
4026 {
4027  *p_def = plsc->chrdef;
4028  *p_ht = plsc->chrht;
4029 }
4030 
4031 // Get viewport boundaries in normalized device coordinates
4032 
4033 void
4034 c_plgvpd( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
4035 {
4036  *p_xmin = plsc->vpdxmi;
4037  *p_xmax = plsc->vpdxma;
4038  *p_ymin = plsc->vpdymi;
4039  *p_ymax = plsc->vpdyma;
4040 }
4041 
4042 // Get viewport boundaries in world coordinates
4043 
4044 void
4045 c_plgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
4046 {
4047  *p_xmin = plsc->vpwxmi;
4048  *p_xmax = plsc->vpwxma;
4049  *p_ymin = plsc->vpwymi;
4050  *p_ymax = plsc->vpwyma;
4051 }
4052 
4053 // Get the viewport boundaries in world coordinates, expanded slightly
4054 void
4055 plP_xgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
4056 {
4057  PLFLT dx, dy;
4058 
4059  dx = ( plsc->vpwxma - plsc->vpwxmi ) * 1.0e-5;
4060  dy = ( plsc->vpwyma - plsc->vpwymi ) * 1.0e-5;
4061 
4062  // The plot window is made slightly larger than requested so that
4063  // the end limits will be on the graph
4064 
4065  *p_xmin = plsc->vpwxmi - dx;
4066  *p_xmax = plsc->vpwxma + dx;
4067  *p_ymin = plsc->vpwymi - dy;
4068  *p_ymax = plsc->vpwyma + dy;
4069 }
4070 
4071 //--------------------------------------------------------------------------
4072 // These should not be called by the user.
4073 //--------------------------------------------------------------------------
4074 
4075 // Get x-y domain in world coordinates for 3d plots
4076 
4077 void
4078 plP_gdom( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
4079 {
4080  *p_xmin = plsc->domxmi;
4081  *p_xmax = plsc->domxma;
4082  *p_ymin = plsc->domymi;
4083  *p_ymax = plsc->domyma;
4084 }
4085 
4086 // Get vertical (z) scale parameters for 3-d plot
4087 
4088 void
4089 plP_grange( PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax )
4090 {
4091  *p_zscl = plsc->zzscl;
4092  *p_zmin = plsc->ranmi;
4093  *p_zmax = plsc->ranma;
4094 }
4095 
4096 // Get parameters used in 3d plots
4097 
4098 void
4099 plP_gw3wc( PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz )
4100 {
4101  *p_dxx = plsc->cxx;
4102  *p_dxy = plsc->cxy;
4103  *p_dyx = plsc->cyx;
4104  *p_dyy = plsc->cyy;
4105  *p_dyz = plsc->cyz;
4106 }
4107 
4108 // Get clip boundaries in physical coordinates
4109 
4110 void
4111 plP_gclp( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax )
4112 {
4113  *p_ixmin = plsc->clpxmi;
4114  *p_ixmax = plsc->clpxma;
4115  *p_iymin = plsc->clpymi;
4116  *p_iymax = plsc->clpyma;
4117 }
4118 
4119 // Set clip boundaries in physical coordinates
4120 
4121 void
4122 plP_sclp( PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax )
4123 {
4124  plsc->clpxmi = ixmin;
4125  plsc->clpxma = ixmax;
4126  plsc->clpymi = iymin;
4127  plsc->clpyma = iymax;
4128 }
4129 
4130 // Get physical device limits in physical coordinates
4131 
4132 void
4133 plP_gphy( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax )
4134 {
4135  *p_ixmin = plsc->phyxmi;
4136  *p_ixmax = plsc->phyxma;
4137  *p_iymin = plsc->phyymi;
4138  *p_iymax = plsc->phyyma;
4139 }
4140 
4141 // Get number of subpages on physical device and current subpage
4142 
4143 void
4144 plP_gsub( PLINT *p_nx, PLINT *p_ny, PLINT *p_cs )
4145 {
4146  *p_nx = plsc->nsubx;
4147  *p_ny = plsc->nsuby;
4148  *p_cs = plsc->cursub;
4149 }
4150 
4151 // Set number of subpages on physical device and current subpage
4152 
4153 void
4154 plP_ssub( PLINT nx, PLINT ny, PLINT cs )
4155 {
4156  plsc->nsubx = nx;
4157  plsc->nsuby = ny;
4158  plsc->cursub = cs;
4159 }
4160 
4161 // Get number of pixels to a millimeter
4162 
4163 void
4164 plP_gpixmm( PLFLT *p_x, PLFLT *p_y )
4165 {
4166  *p_x = plsc->xpmm;
4167  *p_y = plsc->ypmm;
4168 }
4169 
4170 // All the drivers call this to set physical pixels/mm.
4171 
4172 void
4173 plP_setpxl( PLFLT xpmm, PLFLT ypmm )
4174 {
4175  plsc->xpmm = xpmm;
4176  plsc->ypmm = ypmm;
4177  plsc->umx = (PLINT) ( 1000.0 / plsc->xpmm );
4178  plsc->umy = (PLINT) ( 1000.0 / plsc->ypmm );
4179 }
4180 
4181 // Sets up physical limits of plotting device.
4182 
4183 void
4185 {
4186  if ( xmin > xmax || ymin > ymax )
4187  plexit( "plP_setphy: device minima must not exceed maxima" );
4188 
4189  plsc->phyxmi = xmin;
4190  plsc->phyxma = xmax;
4191  plsc->phyymi = ymin;
4192  plsc->phyyma = ymax;
4193  plsc->phyxlen = xmax - xmin;
4194  plsc->phyylen = ymax - ymin;
4195 }
4196 
4197 //--------------------------------------------------------------------------
4198 // void c_plscompression()
4199 //
4200 // Set compression.
4201 // Has to be done before plinit.
4202 //--------------------------------------------------------------------------
4203 
4204 void
4205 c_plscompression( PLINT compression )
4206 {
4207  if ( plsc->level <= 0 )
4208  {
4209  plsc->dev_compression = compression;
4210  }
4211 }
4212 
4213 //--------------------------------------------------------------------------
4214 // void c_plgcompression()
4215 //
4216 // Get compression
4217 //--------------------------------------------------------------------------
4218 
4219 void
4220 c_plgcompression( PLINT *compression )
4221 {
4222  *compression = plsc->dev_compression;
4223 }
4224 
4225 
4226 //--------------------------------------------------------------------------
4227 // void plP_getinitdriverlist()
4228 //
4229 // Check to see if a driver/stream has been initialised
4230 // Returns a space separated list of matches streams/drivers
4231 // If more than one stream uses the same device, then the device name
4232 // will be returned for each stream.
4233 // Caller must allocate enough memory for "names" to hold the answer.
4234 //--------------------------------------------------------------------------
4235 
4236 void
4238 {
4239  int i;
4240 
4241  for ( i = 0; i < PL_NSTREAMS; ++i )
4242  {
4243  if ( pls[i] != NULL )
4244  {
4245  if ( i == 0 )
4246  strcpy( names, pls[i]->DevName );
4247  else
4248  {
4249  strcat( names, " " );
4250  strcat( names, pls[i]->DevName );
4251  }
4252  }
4253  else
4254  break;
4255  }
4256 }
4257 
4258 
4259 //--------------------------------------------------------------------------
4260 // PLINT plP_checkdriverinit()
4261 //
4262 // Checks from a list of given drivers which ones have been initialised
4263 // and returns the number of devices matching the list, or -1 if in error.
4264 // Effectively returns the number of streams matching the given stream.
4265 //--------------------------------------------------------------------------
4266 
4268 {
4269  char *buff;
4270  char *tok = NULL;
4271  PLINT ret = 0; // set up return code to 0, the value if no devices match
4272 
4273  buff = (char *) malloc( (size_t) PL_NSTREAMS * 8 ); // Allocate enough memory for 8
4274  // characters for each possible stream
4275 
4276  if ( buff != NULL )
4277  {
4278  memset( buff, 0, PL_NSTREAMS * 8 ); // Make sure we clear it
4279  plP_getinitdriverlist( buff ); // Get the list of initialised devices
4280 
4281  for ( tok = strtok( buff, " ," ); // Check each device against the "name"
4282  tok; tok = strtok( 0, " ," ) ) // supplied to the subroutine
4283  {
4284  if ( strstr( names, tok ) != NULL ) // Check to see if the device has been initialised
4285  {
4286  ret++; // Bump the return code if it has
4287  }
4288  }
4289  free( buff ); // Clear up that memory we allocated
4290  }
4291  else
4292  ret = -1; // Error flag
4293 
4294  return ( ret );
4295 }
4296 
4297 
4298 //--------------------------------------------------------------------------
4299 // plP_image
4300 //
4301 // Author: Alessandro Mirone, Nov 2001
4302 //
4303 // Updated by Hezekiah Carty, Mar 2008.
4304 // - Added support for pltr callback
4305 // - Commented out the "dev_fastimg" rendering path
4306 //
4307 //--------------------------------------------------------------------------
4308 
4309 void
4311  void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ), PLPointer pltr_data )
4312 {
4313  plsc->page_status = DRAWING;
4314 
4315  plimageslow( z, nx, ny, xmin, ymin, dx, dy, pltr, pltr_data );
4316 
4317  //
4318  // COMMENTED OUT by Hezekiah Carty, March 2008
4319  // The current dev_fastimg rendering method does not work as-is with
4320  // the plimagefr coordinate transform support.
4321  // This is hopefully temporary, until the dev_fastimg rendering
4322  // path can be updated to work with the new plimage internals.
4323  // Until then, all plimage* rendering is done by the plimageslow
4324  // rendering path.
4325  //
4326 #if 0 // BEGIN dev_fastimg COMMENT
4327  PLINT i, npts;
4328  short *xscl, *yscl;
4329  int plbuf_write;
4330 
4331  plsc->page_status = DRAWING;
4332 
4333  if ( plsc->dev_fastimg == 0 )
4334  {
4335  plimageslow( x, y, z, nx - 1, ny - 1,
4336  xmin, ymin, dx, dy, zmin, zmax );
4337  return;
4338  }
4339 
4340  if ( plsc->plbuf_write )
4341  {
4342  IMG_DT img_dt;
4343 
4344  img_dt.xmin = xmin;
4345  img_dt.ymin = ymin;
4346  img_dt.dx = dx;
4347  img_dt.dy = dy;
4348 
4349  plsc->dev_ix = x;
4350  plsc->dev_iy = y;
4351  plsc->dev_z = z;
4352  plsc->dev_nptsX = nx;
4353  plsc->dev_nptsY = ny;
4354  plsc->dev_zmin = zmin;
4355  plsc->dev_zmax = zmax;
4356 
4357  plbuf_esc( plsc, PLESC_IMAGE, &img_dt );
4358  }
4359 
4360  // avoid re-saving plot buffer while in plP_esc()
4361  plbuf_write = plsc->plbuf_write;
4362  plsc->plbuf_write = 0;
4363 
4364  npts = nx * ny;
4365  if ( plsc->difilt ) // isn't this odd? when replaying the plot buffer, e.g., when resizing the window, difilt() is caled again! the plot buffer should already contain the transformed data--it would save a lot of time! (and allow for differently oriented plots when in multiplot mode)
4366  {
4367  PLINT clpxmi, clpxma, clpymi, clpyma;
4368 
4369  if ( ( ( xscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) ||
4370  ( ( yscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) )
4371  {
4372  plexit( "plP_image: Insufficient memory" );
4373  }
4374 
4375  for ( i = 0; i < npts; i++ )
4376  {
4377  xscl[i] = x[i];
4378  yscl[i] = y[i];
4379  }
4380  sdifilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
4381  plsc->imclxmin = clpxmi;
4382  plsc->imclymin = clpymi;
4383  plsc->imclxmax = clpxma;
4384  plsc->imclymax = clpyma;
4385  grimage( xscl, yscl, z, nx, ny );
4386  free( xscl );
4387  free( yscl );
4388  }
4389  else
4390  {
4391  plsc->imclxmin = plsc->phyxmi;
4392  plsc->imclymin = plsc->phyymi;
4393  plsc->imclxmax = plsc->phyxma;
4394  plsc->imclymax = plsc->phyyma;
4395  grimage( x, y, z, nx, ny );
4396  }
4397  plsc->plbuf_write = plbuf_write;
4398 #endif // END dev_fastimg COMMENT
4399 }
4400 
4401 //--------------------------------------------------------------------------
4402 // plstransform
4403 //
4404 // Set a universal coordinate transform function which will be applied to all
4405 // plotted items.
4406 //--------------------------------------------------------------------------
4407 void
4408 c_plstransform( void ( *coordinate_transform )( PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer ), PLPointer coordinate_transform_data )
4409 {
4410  plsc->coordinate_transform = coordinate_transform;
4411  plsc->coordinate_transform_data = coordinate_transform_data;
4412 }