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