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