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