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