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