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