PLplot  5.9.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plctrl.c
Go to the documentation of this file.
1 // $Id: plctrl.c 12242 2012-10-05 21:31:41Z andrewross $
2 //
3 // Misc. control routines, like begin, end, exit, change graphics/text
4 // mode, change color. Includes some spillage from plcore.c. If you
5 // don't know where it should go, put it here.
6 //
7 // Copyright (C) 2004 Joao Cardoso
8 // Copyright (C) 2004 Rafael Laboissiere
9 // Copyright (C) 2008 Hazen Babcock
10 // Copyright (C) 2009 Alan W. Irwin
11 // Copyright (C) 2011 Hezekiah M. Carty
12 //
13 // This file is part of PLplot.
14 //
15 // PLplot is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU Library General Public License as published
17 // by the Free Software Foundation; either version 2 of the License, or
18 // (at your option) any later version.
19 //
20 // PLplot is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU Library General Public License for more details.
24 //
25 // You should have received a copy of the GNU Library General Public License
26 // along with PLplot; if not, write to the Free Software
27 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 //
29 //
30 
36 
37 #define DEBUG
38 
39 #define NEED_PLDEBUG
40 #include "plplotP.h"
41 #ifdef macintosh
42 #include "mac.h"
43 // for plMacLibOpen prototype; used in plLibOpen
44 #endif
45 
46 #ifdef DJGPP // dos386/djgpp
47 #ifdef __unix
48 #undef __unix
49 #endif
50 #endif
51 
52 #ifdef __unix
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #ifdef PL_HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58 #include <errno.h>
59 #endif
60 
61 // Random number generator (Mersenne Twister)
62 #include "mt19937ar.h"
63 
64 #define BUFFER_SIZE 256
65 #define COLLEN 30
66 #define PALLEN 160
67 #define MSGLEN 1024
68 
69 // small epsilon for fuzzy range checks that is still large enough to
70 // work even in the single precision floating point case.
71 #define FUZZ_EPSILON 1.e-4
72 
73 // Static functions
74 
75 // Used by any external init code to suggest a path
77 
78 static void
79 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name );
80 
81 static void
82 strcat_delim( char *dirspec );
83 
84 static int
85 ( *exit_handler )( const char *errormsg );
86 
87 static void
88 ( *abort_handler )( const char *errormsg );
89 
90 static void
91 plcmap0_def( int imin, int imax );
92 
93 static void
94 plcmap1_def( void );
95 
96 static PLFLT
97 value( double n1, double n2, double hue );
98 
99 static char *
100 read_line( char *buffer, int length, FILE *fp );
101 
102 static void
103 cmap0_palette_read( const char *filename,
104  int *number_colors, unsigned int **r, unsigned int **g,
105  unsigned int **b, double **a );
106 
107 // An additional hardwired location for lib files.
108 // I have no plans to change these again, ever.
109 
110 #if defined ( DJGPP )
111 #ifndef PLLIBDEV
112 #define PLLIBDEV "c:/plplot/lib"
113 #endif
114 
115 #elif defined ( MSDOS )
116 #ifndef PLLIBDEV
117 #define PLLIBDEV "c:\\plplot\\lib"
118 #endif
119 
120 #else
121 
122 // Anything else is assumed to be Unix
123 
124 #ifndef PLLIBDEV
125 #define PLLIBDEV "/usr/local/plplot/lib"
126 #endif
127 
128 #endif
129 
130 //--------------------------------------------------------------------------
131 // Routines that deal with colors & color maps.
132 //--------------------------------------------------------------------------
133 
134 //--------------------------------------------------------------------------
135 // plcol0()
136 //
141 
142 void
143 c_plcol0( PLINT icol0 )
144 {
145  if ( plsc->level < 1 )
146  {
147  plabort( "plcol0: Please call plinit first" );
148  return;
149  }
150  if ( icol0 < 0 || icol0 >= plsc->ncol0 )
151  {
152  char buffer[BUFFER_SIZE];
153  snprintf( buffer, BUFFER_SIZE, "plcol0: Invalid color map entry: %d", (int) icol0 );
154  plabort( buffer );
155  return;
156  }
157 
158  plsc->icol0 = icol0;
159  plsc->curcolor.r = plsc->cmap0[icol0].r;
160  plsc->curcolor.g = plsc->cmap0[icol0].g;
161  plsc->curcolor.b = plsc->cmap0[icol0].b;
162  plsc->curcolor.a = plsc->cmap0[icol0].a;
163 
164  plsc->curcmap = 0;
166 }
167 
168 //--------------------------------------------------------------------------
169 // plcol1()
170 //
175 
176 void
178 {
179  PLINT icol1;
180 
181  if ( plsc->level < 1 )
182  {
183  plabort( "plcol1: Please call plinit first" );
184  return;
185  }
186  if ( col1 < 0 || col1 > 1 || isnan( col1 ) )
187  {
188  char buffer[BUFFER_SIZE];
189  snprintf( buffer, BUFFER_SIZE, "plcol1: Invalid color map position: %f", (PLFLT) col1 );
190  plabort( buffer );
191  return;
192  }
193 
194  icol1 = (PLINT) ( col1 * plsc->ncol1 );
195  icol1 = MIN( icol1, plsc->ncol1 - 1 );
196 
197  plsc->icol1 = icol1;
198  plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
199  plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
200  plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
201  plsc->curcolor.a = plsc->cmap1[plsc->icol1].a;
202 
203  plsc->curcmap = 1;
205 }
206 
207 //--------------------------------------------------------------------------
208 // plscolbg()
209 //
215 
216 void
218 {
219  plscol0( 0, r, g, b );
220 }
221 
222 //--------------------------------------------------------------------------
223 // plscolbga()
224 //
232 
233 //--------------------------------------------------------------------------
234 
235 void
237 {
238  plscol0a( 0, r, g, b, a );
239 }
240 
241 //--------------------------------------------------------------------------
242 // plgcolbg()
243 //
249 
250 void
252 {
253  plgcol0( 0, r, g, b );
254 }
255 
256 //--------------------------------------------------------------------------
257 // plgcolbga()
258 //
265 
266 void
268 {
269  plgcol0a( 0, r, g, b, a );
270 }
271 
272 //--------------------------------------------------------------------------
273 // plscol0()
274 //
282 
283 void
284 c_plscol0( PLINT icol0, PLINT r, PLINT g, PLINT b )
285 {
286  if ( plsc->cmap0 == NULL )
287  plscmap0n( 0 );
288  if ( icol0 < 0 || icol0 >= plsc->ncol0 )
289  {
290  char buffer[BUFFER_SIZE];
291  snprintf( buffer, BUFFER_SIZE, "plscol0: Illegal color table value: %d", (int) icol0 );
292  plabort( buffer );
293  return;
294  }
295  if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) )
296  {
297  char buffer[BUFFER_SIZE];
298  snprintf( buffer, BUFFER_SIZE, "plscol0: Invalid RGB color: %d, %d, %d",
299  (int) r, (int) g, (int) b );
300  plabort( buffer );
301  return;
302  }
303 
304  plscol0a( icol0, r, g, b, 1.0 );
305 }
306 
307 //--------------------------------------------------------------------------
308 // plscol0a()
309 //
318 
319 void
320 c_plscol0a( PLINT icol0, PLINT r, PLINT g, PLINT b, PLFLT a )
321 {
322  if ( plsc->cmap0 == NULL )
323  plscmap0n( 0 );
324  if ( icol0 < 0 || icol0 >= plsc->ncol0 )
325  {
326  char buffer[BUFFER_SIZE];
327  snprintf( buffer, BUFFER_SIZE, "plscol0a: Illegal color table value: %d", (int) icol0 );
328  plabort( buffer );
329  return;
330  }
331  if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) || ( a < 0 || a > 1.0 ) )
332  {
333  char buffer[BUFFER_SIZE];
334  snprintf( buffer, BUFFER_SIZE, "plscol0a: Invalid RGB color: %d, %d, %d, %f",
335  (int) r, (int) g, (int) b, (double) a );
336  plabort( buffer );
337  return;
338  }
339 
340  plsc->cmap0[icol0].r = (unsigned char) r;
341  plsc->cmap0[icol0].g = (unsigned char) g;
342  plsc->cmap0[icol0].b = (unsigned char) b;
343  plsc->cmap0[icol0].a = a;
344 
345  if ( plsc->level > 0 )
347 }
348 
349 //--------------------------------------------------------------------------
350 // plgcol0()
351 //
359 
360 void
361 c_plgcol0( PLINT icol0, PLINT *r, PLINT *g, PLINT *b )
362 {
363  if ( plsc->cmap0 == NULL )
364  plscmap0n( 0 );
365 
366  *r = -1;
367  *g = -1;
368  *b = -1;
369 
370  if ( icol0 < 0 || icol0 > plsc->ncol0 )
371  {
372  char buffer[BUFFER_SIZE];
373  snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
374  plabort( buffer );
375  return;
376  }
377 
378  *r = plsc->cmap0[icol0].r;
379  *g = plsc->cmap0[icol0].g;
380  *b = plsc->cmap0[icol0].b;
381 
382  return;
383 }
384 
385 //--------------------------------------------------------------------------
386 // plgcol0a()
387 //
396 
397 void
398 c_plgcol0a( PLINT icol0, PLINT *r, PLINT *g, PLINT *b, PLFLT *a )
399 {
400  if ( plsc->cmap0 == NULL )
401  plscmap0n( 0 );
402 
403  *r = -1;
404  *g = -1;
405  *b = -1;
406  *a = -1.0;
407 
408  if ( icol0 < 0 || icol0 > plsc->ncol0 )
409  {
410  char buffer[BUFFER_SIZE];
411  snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
412  plabort( buffer );
413  return;
414  }
415 
416  *r = plsc->cmap0[icol0].r;
417  *g = plsc->cmap0[icol0].g;
418  *b = plsc->cmap0[icol0].b;
419  *a = plsc->cmap0[icol0].a;
420 
421  return;
422 }
423 
424 //--------------------------------------------------------------------------
425 // plscmap0()
426 //
434 
435 void
436 c_plscmap0( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol0 )
437 {
438  int i;
439 
440  plscmap0n( ncol0 );
441 
442  for ( i = 0; i < plsc->ncol0; i++ )
443  {
444  if ( ( r[i] < 0 || r[i] > 255 ) ||
445  ( g[i] < 0 || g[i] > 255 ) ||
446  ( b[i] < 0 || b[i] > 255 ) )
447  {
448  char buffer[BUFFER_SIZE];
449  snprintf( buffer, BUFFER_SIZE, "plscmap0: Invalid RGB color: %d, %d, %d",
450  (int) r[i], (int) g[i], (int) b[i] );
451  plabort( buffer );
452  return;
453  }
454 
455  plsc->cmap0[i].r = (unsigned char) r[i];
456  plsc->cmap0[i].g = (unsigned char) g[i];
457  plsc->cmap0[i].b = (unsigned char) b[i];
458  plsc->cmap0[i].a = 1.0;
459  }
460 
461  if ( plsc->level > 0 )
463 }
464 
465 //--------------------------------------------------------------------------
466 // plscmap0a()
467 //
476 
477 void
478 c_plscmap0a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *a, PLINT ncol0 )
479 {
480  int i;
481 
482  plscmap0n( ncol0 );
483 
484  for ( i = 0; i < plsc->ncol0; i++ )
485  {
486  if ( ( r[i] < 0 || r[i] > 255 ) ||
487  ( g[i] < 0 || g[i] > 255 ) ||
488  ( b[i] < 0 || b[i] > 255 ) ||
489  ( a[i] < 0.0 || a[i] > 1.0 ) )
490  {
491  char buffer[BUFFER_SIZE];
492  snprintf( buffer, BUFFER_SIZE, "plscmap0a: Invalid RGB color: %d, %d, %d, %f",
493  (int) r[i], (int) g[i], (int) b[i], (double) a[i] );
494  plabort( buffer );
495  return;
496  }
497 
498  plsc->cmap0[i].r = (unsigned char) r[i];
499  plsc->cmap0[i].g = (unsigned char) g[i];
500  plsc->cmap0[i].b = (unsigned char) b[i];
501  plsc->cmap0[i].a = a[i];
502  }
503 
504  if ( plsc->level > 0 )
506 }
507 
508 //--------------------------------------------------------------------------
509 // plscmap1()
510 //
518 
519 void
520 c_plscmap1( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol1 )
521 {
522  int i;
523 
524  plscmap1n( ncol1 );
525 
526  for ( i = 0; i < plsc->ncol1; i++ )
527  {
528  if ( ( r[i] < 0 || r[i] > 255 ) ||
529  ( g[i] < 0 || g[i] > 255 ) ||
530  ( b[i] < 0 || b[i] > 255 ) )
531  {
532  char buffer[BUFFER_SIZE];
533  snprintf( buffer, BUFFER_SIZE, "plscmap1: Invalid RGB color: %d, %d, %d",
534  (int) r[i], (int) g[i], (int) b[i] );
535  plabort( buffer );
536  return;
537  }
538  plsc->cmap1[i].r = (unsigned char) r[i];
539  plsc->cmap1[i].g = (unsigned char) g[i];
540  plsc->cmap1[i].b = (unsigned char) b[i];
541  plsc->cmap1[i].a = 1.0;
542  }
543 
544  if ( plsc->level > 0 )
546 }
547 
548 //--------------------------------------------------------------------------
549 // plscmap1a()
550 //
559 
560 void
561 c_plscmap1a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *a, PLINT ncol1 )
562 {
563  int i;
564 
565  plscmap1n( ncol1 );
566 
567  for ( i = 0; i < plsc->ncol1; i++ )
568  {
569  if ( ( r[i] < 0 || r[i] > 255 ) ||
570  ( g[i] < 0 || g[i] > 255 ) ||
571  ( b[i] < 0 || b[i] > 255 ) ||
572  ( a[i] < 0.0 || a[i] > 1.0 ) )
573  {
574  char buffer[BUFFER_SIZE];
575  snprintf( buffer, BUFFER_SIZE, "plscmap1a: Invalid RGB color: %d, %d, %d, %f",
576  (int) r[i], (int) g[i], (int) b[i], (double) a[i] );
577  plabort( buffer );
578  return;
579  }
580  plsc->cmap1[i].r = (unsigned char) r[i];
581  plsc->cmap1[i].g = (unsigned char) g[i];
582  plsc->cmap1[i].b = (unsigned char) b[i];
583  plsc->cmap1[i].a = a[i];
584  }
585 
586  if ( plsc->level > 0 )
588 }
589 
590 //--------------------------------------------------------------------------
591 // plscmap1l()
592 //
641 
642 void
643 c_plscmap1l( PLINT itype, PLINT npts, const PLFLT *pos,
644  const PLFLT *coord1, const PLFLT *coord2, const PLFLT *coord3, const PLINT *alt_hue_path )
645 {
646  int n;
647  PLFLT h, l, s, r, g, b;
648 
649  if ( npts < 2 )
650  {
651  plabort( "plscmap1l: Must specify at least two control points" );
652  return;
653  }
654 
655  if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) )
656  {
657  plabort( "plscmap1l: First, last control points must lie on boundary" );
658  return;
659  }
660 
661  if ( npts > PL_MAX_CMAP1CP )
662  {
663  plabort( "plscmap1l: exceeded maximum number of control points" );
664  return;
665  }
666 
667 // Allocate if not done yet
668 
669  if ( plsc->cmap1 == NULL )
670  plscmap1n( 0 );
671 
672 // Save control points
673 
674  plsc->ncp1 = npts;
675 
676  for ( n = 0; n < npts; n++ )
677  {
678  if ( itype == 0 )
679  {
680  h = coord1[n];
681  l = coord2[n];
682  s = coord3[n];
683  }
684  else
685  {
686  r = coord1[n];
687  g = coord2[n];
688  b = coord3[n];
689  c_plrgbhls( r, g, b, &h, &l, &s );
690  }
691 
692  plsc->cmap1cp[n].h = h;
693  plsc->cmap1cp[n].l = l;
694  plsc->cmap1cp[n].s = s;
695  plsc->cmap1cp[n].p = pos[n];
696  plsc->cmap1cp[n].a = 1.0;
697 
698  if ( alt_hue_path == NULL )
699  plsc->cmap1cp[n].alt_hue_path = 0;
700  else
701  plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
702  }
703 
704 // Calculate and set color map
705 
706  plcmap1_calc();
707 }
708 
709 //--------------------------------------------------------------------------
710 // plscmap1la()
711 //
723 
724 void
725 c_plscmap1la( PLINT itype, PLINT npts, const PLFLT *pos,
726  const PLFLT *coord1, const PLFLT *coord2, const PLFLT *coord3, const PLFLT *a, const PLINT *alt_hue_path )
727 {
728  int n;
729  PLFLT h, l, s, r, g, b;
730 
731  if ( npts < 2 )
732  {
733  plabort( "plscmap1la: Must specify at least two control points" );
734  return;
735  }
736 
737  if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) )
738  {
739  plabort( "plscmap1la: First, last control points must lie on boundary" );
740  return;
741  }
742 
743  if ( npts > PL_MAX_CMAP1CP )
744  {
745  plabort( "plscmap1la: exceeded maximum number of control points" );
746  return;
747  }
748 
749 // Allocate if not done yet
750 
751  if ( plsc->cmap1 == NULL )
752  plscmap1n( 0 );
753 
754 // Save control points
755 
756  plsc->ncp1 = npts;
757 
758  for ( n = 0; n < npts; n++ )
759  {
760  if ( itype == 0 )
761  {
762  h = coord1[n];
763  l = coord2[n];
764  s = coord3[n];
765  }
766  else
767  {
768  r = coord1[n];
769  g = coord2[n];
770  b = coord3[n];
771  c_plrgbhls( r, g, b, &h, &l, &s );
772  }
773 
774  plsc->cmap1cp[n].h = h;
775  plsc->cmap1cp[n].l = l;
776  plsc->cmap1cp[n].s = s;
777  plsc->cmap1cp[n].p = pos[n];
778  plsc->cmap1cp[n].a = a[n];
779 
780  if ( alt_hue_path == NULL )
781  plsc->cmap1cp[n].alt_hue_path = 0;
782  else
783  plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
784  }
785 
786 // Calculate and set color map
787 
788  plcmap1_calc();
789 }
790 
791 //--------------------------------------------------------------------------
792 // plcmap1_calc()
793 //
796 
797 void
799 {
800  int i, n;
801  PLFLT delta, dp, dh, dl, ds, da;
802  PLFLT h, l, s, p, r, g, b, a;
803 
804 // Loop over all control point pairs
805 
806  for ( n = 0; n < plsc->ncp1 - 1; n++ )
807  {
808  if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n + 1].p )
809  continue;
810 
811  // Differences in p, h, l, s between ctrl pts
812 
813  dp = plsc->cmap1cp[n + 1].p - plsc->cmap1cp[n].p;
814  dh = plsc->cmap1cp[n + 1].h - plsc->cmap1cp[n].h;
815  dl = plsc->cmap1cp[n + 1].l - plsc->cmap1cp[n].l;
816  ds = plsc->cmap1cp[n + 1].s - plsc->cmap1cp[n].s;
817  da = plsc->cmap1cp[n + 1].a - plsc->cmap1cp[n].a;
818 
819  // Adjust dh if we are to go around "the back side"
820 
821  if ( plsc->cmap1cp[n].alt_hue_path )
822  dh = ( dh > 0 ) ? dh - 360 : dh + 360;
823 
824  // Loop over all color cells. Only interested in cells located (in
825  // cmap1 space) between n_th and n+1_th control points
826 
827  for ( i = 0; i < plsc->ncol1; i++ )
828  {
829  p = (double) i / ( plsc->ncol1 - 1.0 );
830  if ( ( p < plsc->cmap1cp[n].p ) ||
831  ( p > plsc->cmap1cp[n + 1].p ) )
832  continue;
833 
834  // Interpolate based on position of color cell in cmap1 space
835 
836  delta = ( p - plsc->cmap1cp[n].p ) / dp;
837 
838  // Linearly interpolate to get color cell h, l, s values
839 
840  h = plsc->cmap1cp[n].h + dh * delta;
841  l = plsc->cmap1cp[n].l + dl * delta;
842  s = plsc->cmap1cp[n].s + ds * delta;
843  a = plsc->cmap1cp[n].a + da * delta;
844 
845  while ( h >= 360. )
846  h -= 360.;
847 
848  while ( h < 0. )
849  h += 360.;
850 
851  c_plhlsrgb( h, l, s, &r, &g, &b );
852 
853  plsc->cmap1[i].r = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
854  plsc->cmap1[i].g = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
855  plsc->cmap1[i].b = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
856  plsc->cmap1[i].a = a;
857  }
858  }
859 
860  if ( plsc->level > 0 )
862 }
863 
864 //--------------------------------------------------------------------------
876 //--------------------------------------------------------------------------
877 
878 void
879 c_plscmap1_range( PLFLT min_color, PLFLT max_color )
880 {
881  if ( min_color > max_color || max_color < 0.0 || min_color > 1.0 )
882  {
883  plwarn( "plscmap1_range called with invalid color range" );
884  return;
885  }
886  if ( min_color < 0.0 )
887  {
888  plwarn( "plscmap1_range called with a negative minimum color value" );
889  min_color = 0.0;
890  }
891  if ( max_color > 1.0 )
892  {
893  plwarn( "plscmap1_range called with an out of range maximum color value" );
894  max_color = 1.0;
895  }
896  plsc->cmap1_min = min_color;
897  plsc->cmap1_max = max_color;
898 }
899 
900 //--------------------------------------------------------------------------
905 //--------------------------------------------------------------------------
906 
907 void
908 c_plgcmap1_range( PLFLT *min_color, PLFLT *max_color )
909 {
910  *min_color = plsc->cmap1_min;
911  *max_color = plsc->cmap1_max;
912 }
913 
914 //--------------------------------------------------------------------------
915 // plscmap0n()
916 //
924 
925 void
927 {
928  int ncol, size, imin, imax;
929 
930 // No change
931 
932  if ( ncol0 > 0 && plsc->ncol0 == ncol0 )
933  return;
934 
935 // Handle all possible startup conditions
936 
937  if ( plsc->ncol0 <= 0 && ncol0 <= 0 )
938  ncol = 16;
939  else if ( ncol0 <= 0 )
940  ncol = plsc->ncol0;
941  else
942  ncol = ncol0;
943 
944  imax = ncol - 1;
945  size = ncol * (int) sizeof ( PLColor );
946 
947 // Allocate the space
948 
949  if ( plsc->cmap0 == NULL )
950  {
951  if ( ( plsc->cmap0 = (PLColor *) calloc( 1, (size_t) size ) ) == NULL )
952  {
953  plexit( "c_plscmap0n: Insufficient memory" );
954  }
955  imin = 0;
956  }
957  else
958  {
959  if ( ( plsc->cmap0 = (PLColor *) realloc( plsc->cmap0, (size_t) size ) ) == NULL )
960  {
961  plexit( "c_plscmap0n: Insufficient memory" );
962  }
963  imin = plsc->ncol0;
964  }
965 
966 // Fill in default entries
967 
968  plsc->ncol0 = ncol;
969  plcmap0_def( imin, imax );
970 
971  if ( plsc->level > 0 )
973 }
974 
975 //--------------------------------------------------------------------------
976 // color_set()
977 //
986 
987 void
988 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name )
989 {
990  plsc->cmap0[i].r = r;
991  plsc->cmap0[i].g = g;
992  plsc->cmap0[i].b = b;
993  plsc->cmap0[i].a = a;
994  plsc->cmap0[i].name = name;
995 }
996 
997 #define color_def( i, r, g, b, a, n ) \
998  if ( i >= imin && i <= imax ) color_set( i, r, g, b, a, n );
999 
1000 //--------------------------------------------------------------------------
1001 // plcmap0_def()
1002 //
1008 
1009 void
1010 plcmap0_def( int imin, int imax )
1011 {
1012  int i;
1013  unsigned int *r, *g, *b;
1014  double *a;
1015  int number_colors;
1016  if ( imin <= imax )
1017  {
1018  cmap0_palette_read( "", &number_colors, &r, &g, &b, &a );
1019  for ( i = imin; i <= MIN( ( number_colors - 1 ), imax ); i++ )
1020  color_def( i, (U_CHAR) r[i], (U_CHAR) g[i], (U_CHAR) b[i], a[i],
1021  "colors defined by default cmap0 palette file" );
1022  free( r );
1023  free( g );
1024  free( b );
1025  free( a );
1026  }
1027  else
1028  {
1029  number_colors = 0;
1030  }
1031 
1032  // Initialize all colours undefined by the default colour palette file
1033  // to opaque red as a warning.
1034  for ( i = MAX( number_colors, imin ); i <= imax; i++ )
1035  color_def( i, 255, 0, 0, 1.0,
1036  "opaque red colour to mark not defined by palette file" );
1037 }
1038 
1039 //--------------------------------------------------------------------------
1040 // plscmap1n()
1041 //
1049 
1050 void
1052 {
1053  PLINT ncol;
1054  size_t size;
1055 
1056 // No change
1057 
1058  if ( ncol1 > 0 && plsc->ncol1 == ncol1 )
1059  return;
1060 
1061 // Handle all possible startup conditions
1062 
1063  if ( plsc->ncol1 <= 0 && ncol1 <= 0 )
1064  ncol = 128;
1065  else if ( ncol1 <= 0 )
1066  ncol = plsc->ncol1;
1067  else
1068  ncol = ncol1;
1069 
1070  size = (size_t) ncol * sizeof ( PLColor );
1071 
1072 // Allocate the space
1073 
1074  if ( plsc->ncol1 > 0 )
1075  {
1076  if ( ( plsc->cmap1 = (PLColor *) realloc( plsc->cmap1, size ) ) == NULL )
1077  {
1078  plexit( "c_plscmap1n: Insufficient memory" );
1079  }
1080  }
1081  else
1082  {
1083  if ( ( plsc->cmap1 = (PLColor *) calloc( (size_t) ncol, sizeof ( PLColor ) ) ) == NULL )
1084  {
1085  plexit( "c_plscmap1n: Insufficient memory" );
1086  }
1087  }
1088 
1089 // Fill in default entries
1090 
1091  plsc->ncol1 = ncol;
1092  if ( plsc->ncp1 == 0 )
1093  plcmap1_def();
1094  else
1095  plcmap1_calc();
1096 }
1097 
1098 //--------------------------------------------------------------------------
1099 // plcmap1_def()
1100 //
1110 
1111 void
1113 {
1114  PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
1115 
1116 // Positions of control points
1117 
1118  i[0] = 0; // left boundary
1119  i[1] = 0.44; // a little left of center
1120  i[2] = 0.50; // at center
1121  i[3] = 0.50; // at center
1122  i[4] = 0.56; // a little right of center
1123  i[5] = 1; // right boundary
1124 
1125 // For center control points, pick black or white, whichever is closer to bg
1126 // Be careful to pick just short of top or bottom else hue info is lost
1127 
1128  if ( plsc->cmap0 != NULL )
1129  vertex = ( (PLFLT) plsc->cmap0[0].r +
1130  (PLFLT) plsc->cmap0[0].g +
1131  (PLFLT) plsc->cmap0[0].b ) / 3. / 255.;
1132 
1133  if ( vertex < 0.5 )
1134  {
1135  vertex = 0.01;
1136  midpt = 0.10;
1137  }
1138  else
1139  {
1140  vertex = 0.99;
1141  midpt = 0.90;
1142  }
1143 
1144 // Set hue
1145 
1146  h[0] = 260; // low: blue-violet
1147  h[1] = 260; // only change as we go over vertex
1148  h[2] = 260; // only change as we go over vertex
1149  h[3] = 0; // high: red
1150  h[4] = 0; // high: red
1151  h[5] = 0; // keep fixed
1152 
1153 // Set lightness
1154 
1155  l[0] = 0.5; // low
1156  l[1] = midpt; // midpoint value
1157  l[2] = vertex; // bg
1158  l[3] = vertex; // bg
1159  l[4] = midpt; // midpoint value
1160  l[5] = 0.5; // high
1161 
1162 // Set saturation -- keep at maximum
1163 
1164  s[0] = 1;
1165  s[1] = 1;
1166  s[2] = 1;
1167  s[3] = 1;
1168  s[4] = 1;
1169  s[5] = 1;
1170 
1171  c_plscmap1l( 0, 6, i, h, l, s, NULL );
1172 
1173  if ( plsc->level > 0 )
1175 }
1176 
1177 //--------------------------------------------------------------------------
1178 // plscolor()
1179 //
1183 //--------------------------------------------------------------------------
1184 
1185 void
1187 {
1188  plsc->colorset = 1;
1189  plsc->color = color;
1190 }
1191 
1192 //--------------------------------------------------------------------------
1193 // void value()
1194 //
1200 //--------------------------------------------------------------------------
1201 
1202 PLFLT
1203 value( double n1, double n2, double hue )
1204 {
1205  PLFLT val;
1206 
1207  while ( hue >= 360. )
1208  hue -= 360.;
1209  while ( hue < 0. )
1210  hue += 360.;
1211 
1212  if ( hue < 60. )
1213  val = n1 + ( n2 - n1 ) * hue / 60.;
1214  else if ( hue < 180. )
1215  val = n2;
1216  else if ( hue < 240. )
1217  val = n1 + ( n2 - n1 ) * ( 240. - hue ) / 60.;
1218  else
1219  val = n1;
1220 
1221  return ( val );
1222 }
1223 
1224 //--------------------------------------------------------------------------
1225 // void c_plhlsrgb()
1226 //
1243 
1244 void
1245 c_plhlsrgb( PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b )
1246 {
1247  PLFLT m1, m2;
1248 
1249  if ( l <= .5 )
1250  m2 = l * ( s + 1. );
1251  else
1252  m2 = l + s - l * s;
1253 
1254  m1 = 2 * l - m2;
1255 
1256  *p_r = value( m1, m2, h + 120. );
1257  *p_g = value( m1, m2, h );
1258  *p_b = value( m1, m2, h - 120. );
1259 }
1260 
1261 //--------------------------------------------------------------------------
1262 // void c_plrgbhls()
1263 //
1276 
1277 void
1278 c_plrgbhls( PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s )
1279 {
1280  PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
1281 
1282  rgb_min = MIN( r, MIN( g, b ) );
1283  rgb_max = MAX( r, MAX( g, b ) );
1284 
1285  l = ( rgb_min + rgb_max ) / 2.0;
1286 
1287  if ( rgb_min == rgb_max )
1288  {
1289  s = 0;
1290  h = 0;
1291  }
1292  else
1293  {
1294  d = rgb_max - rgb_min;
1295  if ( l < 0.5 )
1296  s = 0.5 * d / l;
1297  else
1298  s = 0.5 * d / ( 1. - l );
1299 
1300  rc = ( rgb_max - r ) / d;
1301  gc = ( rgb_max - g ) / d;
1302  bc = ( rgb_max - b ) / d;
1303 
1304  if ( r == rgb_max )
1305  h = bc - gc;
1306  else if ( g == rgb_max )
1307  h = rc - bc + 2;
1308  else
1309  h = gc - rc - 2;
1310 
1311  h = h * 60;
1312  if ( h < 0 )
1313  h = h + 360;
1314  else if ( h >= 360 )
1315  h = h - 360;
1316  }
1317  *p_h = h;
1318  *p_l = l;
1319  *p_s = s;
1320 }
1321 
1322 //--------------------------------------------------------------------------
1323 // read_line()
1324 //
1334 
1335 static char *
1336 read_line( char *buffer, int length, FILE *fp )
1337 {
1338  char *pchr;
1339 
1340  // Read the string
1341  if ( fgets( buffer, length, fp ) == NULL )
1342  {
1343  return NULL;
1344  }
1345 
1346  // Sanitize the string we read - it may contain EOL characters
1347  // Make sure file reading starts at the next line
1348  pchr = strchr( buffer, '\n' );
1349  if ( pchr != NULL )
1350  {
1351  *pchr = '\0';
1352  }
1353  else
1354  {
1355  if ( fscanf( fp, "%*[^\n]\n" ) == EOF && ferror( fp ) )
1356  {
1357  return NULL;
1358  }
1359  }
1360 
1361 
1362  pchr = strchr( buffer, '\r' );
1363  if ( pchr != NULL )
1364  {
1365  *pchr = '\0';
1366  }
1367 
1368  // Remove trailing blanks
1369  pchr = buffer + strlen( buffer ) - 1;
1370  while ( pchr != buffer && *pchr == ' ' )
1371  {
1372  *pchr = '\0';
1373  pchr--;
1374  }
1375 
1376  return buffer;
1377 }
1378 
1379 //--------------------------------------------------------------------------
1380 // cmap0_palette_read()
1381 //
1391 
1392 void
1393 cmap0_palette_read( const char *filename,
1394  int *number_colors, unsigned int **r, unsigned int **g, unsigned int **b, double **a )
1395 {
1396  int i, err = 0;
1397  char color_info[COLLEN];
1398  char msgbuf[MSGLEN];
1399  FILE *fp;
1400  char * save_locale = plsave_set_locale();
1401 
1402  if ( strlen( filename ) == 0 )
1403  {
1405  if ( fp == NULL )
1406  {
1407  snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
1408  plwarn( msgbuf );
1409  err = 1;
1410  }
1411  }
1412  else
1413  {
1414  fp = plLibOpen( filename );
1415  if ( fp == NULL )
1416  {
1417  snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", filename );
1418  plwarn( msgbuf );
1419  err = 1;
1420  }
1421  }
1422  if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) )
1423  {
1424  fclose( fp );
1425  snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 header\n" );
1426  plwarn( msgbuf );
1427  err = 1;
1428  }
1429 
1430  if ( !err )
1431  {
1432  // Allocate arrays to hold r, g, b, and a data for calling routine.
1433  // The caller must free these after it is finished with them.
1434  if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1435  ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1436  ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1437  ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
1438  {
1439  fclose( fp );
1440  plexit( "cmap0_palette_read: insufficient memory" );
1441  }
1442 
1443  for ( i = 0; i < *number_colors; i++ )
1444  {
1445  if ( read_line( color_info, COLLEN, fp ) == NULL )
1446  {
1447  err = 1;
1448  break;
1449  }
1450 
1451  // Get the color data
1452  if ( strlen( color_info ) == 7 )
1453  {
1454  if ( sscanf( color_info, "#%2x%2x%2x",
1455  (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
1456  (unsigned int *) ( *b + i ) ) != 3 )
1457  {
1458  err = 1;
1459  break;
1460  }
1461  *( *a + i ) = 1.0;
1462  }
1463  else if ( strlen( color_info ) > 9 )
1464  {
1465  if ( sscanf( color_info, "#%2x%2x%2x %lf",
1466  (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
1467  (unsigned int *) ( *b + i ), (double *) ( *a + i ) ) != 4 )
1468  {
1469  err = 1;
1470  break;
1471  }
1472  // fuzzy range check.
1473  if ( *( *a + i ) < -FUZZ_EPSILON || *( *a + i ) > ( 1. + FUZZ_EPSILON ) )
1474  {
1475  err = 1;
1476  break;
1477  }
1478  else if ( *( *a + i ) < 0. )
1479  {
1480  *( *a + i ) = 0.;
1481  }
1482  else if ( *( *a + i ) > 1. )
1483  {
1484  *( *a + i ) = 1.;
1485  }
1486  }
1487  else
1488  {
1489  err = 1;
1490  break;
1491  }
1492  }
1493  fclose( fp );
1494  if ( err )
1495  {
1496  snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 format data line. Line is %s\n",
1497  color_info );
1498  plwarn( msgbuf );
1499  free( *r );
1500  free( *g );
1501  free( *b );
1502  free( *a );
1503  }
1504  }
1505  // Fall back to opaque red on opaque white as visual warning of any
1506  // error above.
1507  if ( err )
1508  {
1509  *number_colors = 16;
1510  if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( int ) ) ) == NULL ) ||
1511  ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1512  ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1513  ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
1514  {
1515  plexit( "cmap0_palette_read: insufficient memory" );
1516  }
1517  **r = 255;
1518  **g = 255;
1519  **b = 255;
1520  **a = 1.;
1521  for ( i = 1; i < *number_colors; i++ )
1522  {
1523  *( *r + i ) = 255;
1524  *( *g + i ) = 0;
1525  *( *b + i ) = 0;
1526  *( *a + i ) = 1.0;
1527  }
1528  }
1529 
1530  plrestore_locale( save_locale );
1531 }
1532 
1533 //--------------------------------------------------------------------------
1534 // void c_plspal0(filename)
1535 //
1540 
1541 void
1542 c_plspal0( const char *filename )
1543 {
1544  int i;
1545  unsigned int *r, *g, *b;
1546  double *a;
1547  int number_colors;
1548  cmap0_palette_read( filename, &number_colors, &r, &g, &b, &a );
1549  // Allocate default number of cmap0 colours if cmap0 allocation not
1550  // done already.
1551  plscmap0n( 0 );
1552  // Allocate sufficient cmap0 colours to contain present data.
1553  if ( number_colors > plsc->ncol0 )
1554  {
1555  plscmap0n( number_colors );
1556  }
1557  for ( i = 0; i < number_colors; i++ )
1558  {
1559  c_plscol0a( i, (PLINT) r[i], (PLINT) g[i], (PLINT) b[i], a[i] );
1560  }
1561  free( r );
1562  free( g );
1563  free( b );
1564  free( a );
1565 }
1566 
1576 #define fuzzy_range_check( value, min, max, fuzz, err_number ) \
1577  if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) { \
1578  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format data line. Error number is %d. Line is %s\n", err_number, color_info ); \
1579  plwarn( msgbuf ); \
1580  err = 1; \
1581  break; \
1582  } else if ( value < min ) { \
1583  value = min; \
1584  } else if ( value > max ) { \
1585  value = max; \
1586  }
1587 
1588 //--------------------------------------------------------------------------
1589 // void c_plspal1(filename)
1590 //
1596 
1597 void
1598 c_plspal1( const char *filename, PLBOOL interpolate )
1599 {
1600  int i;
1601  int number_colors;
1602  int format_version, err;
1603  PLBOOL rgb;
1604  char color_info[PALLEN];
1605  unsigned int r_i, g_i, b_i;
1606  int pos_i, alt_hue_path_i;
1607  double r_d, g_d, b_d, a_d, pos_d;
1608  PLFLT *r, *g, *b, *a, *pos;
1609  PLINT *ri, *gi, *bi;
1610  PLBOOL *alt_hue_path;
1611  FILE *fp;
1612  char msgbuf[MSGLEN];
1613  char * save_locale = plsave_set_locale();
1614 
1615  rgb = TRUE;
1616  err = 0;
1617  format_version = 0;
1618  if ( strlen( filename ) == 0 )
1619  {
1621  if ( fp == NULL )
1622  {
1623  snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
1624  plwarn( msgbuf );
1625  goto finish;
1626  }
1627  }
1628  else
1629  {
1630  fp = plLibOpen( filename );
1631  if ( fp == NULL )
1632  {
1633  snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", filename );
1634  plwarn( msgbuf );
1635  goto finish;
1636  }
1637  }
1638  // Check for new file format
1639  if ( read_line( color_info, PALLEN, fp ) == NULL )
1640  {
1641  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1642  plwarn( msgbuf );
1643  fclose( fp );
1644  goto finish;
1645  }
1646  if ( strncmp( color_info, "v2 ", 2 ) == 0 )
1647  {
1648  format_version = 1;
1649  if ( strncmp( &color_info[3], "hls", 3 ) == 0 )
1650  rgb = FALSE;
1651  else if ( strncmp( &color_info[3], "rgb", 3 ) == 0 )
1652  rgb = TRUE;
1653  else
1654  {
1655  snprintf( msgbuf, MSGLEN, "Invalid color space %s - assuming RGB\n", &color_info[3] );
1656  plwarn( msgbuf );
1657  rgb = TRUE;
1658  }
1659  if ( read_line( color_info, PALLEN, fp ) == NULL )
1660  {
1661  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1662  plwarn( msgbuf );
1663  fclose( fp );
1664  goto finish;
1665  }
1666  }
1667 
1668  if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 )
1669  {
1670  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
1671  plwarn( msgbuf );
1672  fclose( fp );
1673  goto finish;
1674  }
1675 
1676  r = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1677  g = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1678  b = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1679  ri = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1680  gi = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1681  bi = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1682  a = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1683  pos = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1684  alt_hue_path = (PLBOOL *) malloc( (size_t) number_colors * sizeof ( PLBOOL ) );
1685 
1686  if ( format_version == 0 )
1687  {
1688  int return_sscanf = -1, return_sscanf_old = 0;
1689  // Old tk file format
1690  for ( i = 0; i < number_colors; i++ )
1691  {
1692  if ( read_line( color_info, PALLEN, fp ) == NULL )
1693  {
1694  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1695  plwarn( msgbuf );
1696  fclose( fp );
1697  goto finish;
1698  }
1699  // Ensure string is null terminated if > 160 characters
1700  color_info[PALLEN - 1] = '\0';
1701  return_sscanf = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &alt_hue_path_i );
1702  if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) )
1703  {
1704  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
1705  plwarn( msgbuf );
1706  err = 1;
1707  break;
1708  }
1709  return_sscanf_old = return_sscanf;
1710  // For old format, input colours range from 0 to 255 and
1711  // need to be renormalized to the range from 0. to 1..
1712  r[i] = (PLFLT) r_i / 255.;
1713  g[i] = (PLFLT) g_i / 255.;
1714  b[i] = (PLFLT) b_i / 255.;
1715  a[i] = 1.0;
1716  pos[i] = 0.01 * (PLFLT) pos_i;
1717  fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 1 );
1718  fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 2 );
1719  fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 3 );
1720  fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 4 );
1721  if ( return_sscanf == 5 )
1722  {
1723  // Next to oldest tk format with alt_hue_path specified.
1724  alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
1725  }
1726  }
1727  if ( return_sscanf == 4 )
1728  {
1729  // Oldest tk format. No alt_hue_path specified.
1730  free( alt_hue_path );
1731  alt_hue_path = NULL;
1732  }
1733  }
1734  else
1735  {
1736  // New floating point file version with support for alpha and alt_hue_path values
1737  for ( i = 0; i < number_colors; i++ )
1738  {
1739  if ( read_line( color_info, PALLEN, fp ) == NULL )
1740  {
1741  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1742  plwarn( msgbuf );
1743  fclose( fp );
1744  goto finish;
1745  }
1746  if ( sscanf( color_info, "%lf %lf %lf %lf %lf %d", &pos_d, &r_d, &g_d, &b_d, &a_d, &alt_hue_path_i ) != 6 )
1747  {
1748  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
1749  plwarn( msgbuf );
1750  err = 1;
1751  break;
1752  }
1753 
1754  r[i] = (PLFLT) r_d;
1755  g[i] = (PLFLT) g_d;
1756  b[i] = (PLFLT) b_d;
1757  a[i] = (PLFLT) a_d;
1758  pos[i] = (PLFLT) pos_d;
1759  // Check that all rgba and pos data within range from 0. to
1760  // 1. except for the hls colour space case where the first
1761  // coordinate is checked within range from 0. to 360.
1762  if ( rgb )
1763  {
1764  fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 5 );
1765  }
1766  else
1767  {
1768  fuzzy_range_check( r[i], 0., 360., ( 360. * FUZZ_EPSILON ), 6 );
1769  }
1770  fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 7 );
1771  fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 8 );
1772  fuzzy_range_check( a[i], 0., 1., FUZZ_EPSILON, 9 );
1773  fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 10 );
1774 
1775  alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
1776  }
1777  }
1778  fclose( fp );
1779 
1780  if ( !err )
1781  {
1782  if ( interpolate )
1783  {
1784  c_plscmap1la( rgb, number_colors, pos, r, g, b, a, alt_hue_path );
1785  }
1786  else
1787  {
1788  for ( i = 0; i < number_colors; i++ )
1789  {
1790  ri[i] = (PLINT) ( r[i] * 255.0 );
1791  gi[i] = (PLINT) ( g[i] * 255.0 );
1792  bi[i] = (PLINT) ( b[i] * 255.0 );
1793  }
1794  c_plscmap1a( ri, gi, bi, a, number_colors );
1795  }
1796  }
1797  else
1798  {
1799  // Fall back to red scale as visual warning if some problem occurred
1800  // above.
1801  free( r );
1802  free( g );
1803  free( b );
1804  free( pos );
1805  number_colors = 2;
1806  r = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1807  g = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1808  b = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1809  pos = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1810  r[0] = 0.;
1811  r[1] = 1.;
1812  g[0] = 0.;
1813  g[1] = 0.;
1814  b[0] = 0.;
1815  b[1] = 0.;
1816  pos[0] = 0.;
1817  pos[1] = 1.;
1818  c_plscmap1l( TRUE, number_colors, pos, r, g, b, NULL );
1819  }
1820 
1821  free( r );
1822  free( g );
1823  free( b );
1824  free( ri );
1825  free( gi );
1826  free( bi );
1827  free( a );
1828  free( pos );
1829  free( alt_hue_path );
1830 
1831 finish: plrestore_locale( save_locale );
1832 }
1833 
1834 //--------------------------------------------------------------------------
1835 // A grab-bag of various control routines.
1836 //--------------------------------------------------------------------------
1837 
1838 //--------------------------------------------------------------------------
1839 // void plwarn()
1840 //
1844 
1845 void
1846 plwarn( const char *errormsg )
1847 {
1848  int was_gfx = 0;
1849 
1850  if ( plsc->graphx == 1 )
1851  {
1852  was_gfx = 1;
1853  pltext();
1854  }
1855 
1856  fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
1857  if ( *errormsg != '\0' )
1858  fprintf( stderr, "%s\n", errormsg );
1859 
1860  if ( was_gfx == 1 )
1861  plgra();
1862 }
1863 
1864 //--------------------------------------------------------------------------
1865 // void plabort()
1866 //
1875 
1876 void
1877 plabort( const char *errormsg )
1878 {
1879  if ( abort_handler != NULL )
1880  ( *abort_handler )( errormsg );
1881 
1882  if ( plsc->errcode != NULL )
1883  *( plsc->errcode ) = 1;
1884 
1885  if ( plsc->errmsg != NULL )
1886  {
1887  sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
1888  if ( *errormsg != '\0' )
1889  sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg );
1890  }
1891  else
1892  {
1893  int was_gfx = 0;
1894 
1895  if ( plsc->graphx == 1 )
1896  {
1897  was_gfx = 1;
1898  pltext();
1899  }
1900 
1901  fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
1902  if ( *errormsg != '\0' )
1903  fprintf( stderr, "%s, aborting operation\n", errormsg );
1904 
1905  if ( was_gfx == 1 )
1906  plgra();
1907  }
1908 }
1909 
1910 
1911 //--------------------------------------------------------------------------
1912 // void plsabort()
1913 //
1918 //--------------------------------------------------------------------------
1919 
1920 void
1921 plsabort( void ( *handler )( const char * ) )
1922 {
1923  abort_handler = handler;
1924 }
1925 
1926 //--------------------------------------------------------------------------
1927 // void plexit()
1928 //
1938 //--------------------------------------------------------------------------
1939 
1940 void
1941 plexit( const char *errormsg )
1942 {
1943  int status = 1;
1944 
1945  if ( exit_handler != NULL )
1946  status = ( *exit_handler )( errormsg );
1947 
1948  plsc->nopause = 1;
1949  if ( *errormsg != '\0' )
1950  {
1951  fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
1952  fprintf( stderr, "%s\n", errormsg );
1953  }
1954  plend();
1955 
1956  fprintf( stderr, "Program aborted\n" );
1957  exit( status );
1958 }
1959 
1960 //--------------------------------------------------------------------------
1961 // void plsexit()
1962 //
1967 //--------------------------------------------------------------------------
1968 
1969 void
1970 plsexit( int ( *handler )( const char * ) )
1971 {
1972  exit_handler = handler;
1973 }
1974 
1975 //--------------------------------------------------------------------------
1976 // void plgra()
1977 //
1983 //--------------------------------------------------------------------------
1984 
1985 void
1986 c_plgra( void )
1987 {
1988  if ( plsc->level > 0 )
1989  plP_esc( PLESC_GRAPH, NULL );
1990 }
1991 
1992 //--------------------------------------------------------------------------
1993 // void plxormod()
1994 //
1999 
2000 void
2001 c_plxormod( PLINT mode, PLINT *status ) // xor mode
2002 {
2003  static int ostate = 0;
2004 
2005  if ( !plsc->dev_xor )
2006  {
2007  *status = 0;
2008  return;
2009  }
2010 
2011  if ( plsc->level > 0 )
2012  {
2013  plP_esc( PLESC_XORMOD, &mode );
2014  if ( mode )
2015  {
2016  ostate = plsc->plbuf_write;
2017  plsc->plbuf_write = 0;
2018  }
2019  else
2020  plsc->plbuf_write = ostate;
2021  }
2022  *status = 1;
2023 }
2024 
2025 //--------------------------------------------------------------------------
2030 void
2032 {
2033  if ( !plsc->dev_modeset )
2034  {
2035  plwarn( "plsdrawmode: Mode setting is not supported" );
2036  }
2037  else if ( plsc->level > 0 )
2038  {
2039  plP_esc( PLESC_MODESET, &mode );
2040  }
2041  else
2042  {
2043  plwarn( "plsdrawmode: Initialize PLplot first" );
2044  }
2045  return;
2046 }
2047 
2048 //--------------------------------------------------------------------------
2053 PLINT
2055 {
2056  PLINT mode;
2057 
2058  if ( !plsc->dev_modeset )
2059  {
2060  plwarn( "plgdrawmode: Mode getting is not supported" );
2061  mode = PL_DRAWMODE_UNKNOWN;
2062  }
2063  else if ( plsc->level > 0 )
2064  {
2065  plP_esc( PLESC_MODEGET, &mode );
2066  }
2067  else
2068  {
2069  plwarn( "plsdrawmode: Initialize PLplot first" );
2070  mode = PL_DRAWMODE_UNKNOWN;
2071  }
2072 
2073  return ( mode );
2074 }
2075 
2076 //--------------------------------------------------------------------------
2077 // void pltext()
2078 //
2080 //--------------------------------------------------------------------------
2081 
2082 void
2083 c_pltext( void )
2084 {
2085  if ( plsc->level > 0 )
2086  plP_esc( PLESC_TEXT, NULL );
2087 }
2088 
2089 //--------------------------------------------------------------------------
2090 // void pl_cmd()
2091 //
2098 //--------------------------------------------------------------------------
2099 
2100 void
2101 pl_cmd( PLINT op, void *ptr )
2102 {
2103  plP_esc( op, ptr );
2104 }
2105 
2106 //--------------------------------------------------------------------------
2107 // char *plFindCommand
2108 //
2125 //--------------------------------------------------------------------------
2126 
2127 char *
2128 plFindCommand( const char *fn )
2129 {
2130  char *fs = NULL, *dn;
2131 
2132  //*** see if in build tree **
2133  if ( plInBuildTree() == 1 )
2134  {
2135  plGetName( BUILD_DIR, "bindings/tk", fn, &fs );
2136  if ( !plFindName( fs ) )
2137  return fs;
2138  else
2139  {
2140  plGetName( SOURCE_DIR, "scripts", fn, &fs );
2141  if ( !plFindName( fs ) )
2142  return fs;
2143  }
2144  }
2145 
2146 // PLPLOT_BIN_ENV = $(PLPLOT_BIN)
2147 
2148 #if defined ( PLPLOT_BIN_ENV )
2149  if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL )
2150  {
2151  plGetName( dn, "", fn, &fs );
2152  if ( !plFindName( fs ) )
2153  return fs;
2154  fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); // what IS set?
2155  }
2156 #endif // PLPLOT_BIN_ENV
2157 
2158 // Current directory
2159 
2160  plGetName( ".", "", fn, &fs );
2161  if ( !plFindName( fs ) )
2162  return fs;
2163 
2164 // PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
2165 
2166 #if defined ( PLPLOT_HOME_ENV )
2167  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2168  {
2169  plGetName( dn, "bin", fn, &fs );
2170  if ( !plFindName( fs ) )
2171  return fs;
2172  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2173  }
2174 #endif // PLPLOT_HOME_ENV
2175 
2176 // BIN_DIR
2177 
2178 #if defined ( BIN_DIR )
2179  plGetName( BIN_DIR, "", fn, &fs );
2180  if ( !plFindName( fs ) )
2181  return fs;
2182 #endif
2183 
2184 // Crapped out
2185 
2186  free_mem( fs );
2187  fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn );
2188 #if defined ( BIN_DIR )
2189  fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" ); // what WAS set?
2190 #endif // BIN_DIR
2191  return NULL;
2192 }
2193 
2194 //--------------------------------------------------------------------------
2195 // FILE *plLibOpen(fn)
2196 //
2208 //--------------------------------------------------------------------------
2209 
2210 FILE *
2211 plLibOpen( const char *fn )
2212 {
2213  FILE *ret = NULL;
2214 
2215  PDFstrm *pdfs = plLibOpenPdfstrm( fn );
2216  if ( pdfs == NULL )
2217  {
2218  return NULL;
2219  }
2220  if ( pdfs->file != NULL )
2221  {
2222  ret = pdfs->file;
2223  pdfs->file = NULL;
2224  }
2225  pdf_close( pdfs );
2226  return ret;
2227 }
2228 
2229 //--------------------------------------------------------------------------
2230 // FILE *plLibOpenPdfstrm(fn)
2231 //
2243 //--------------------------------------------------------------------------
2244 PDFstrm *
2245 plLibOpenPdfstrm( const char *fn )
2246 {
2247  PDFstrm *file;
2248  char *fs = NULL, *dn = NULL;
2249 
2250 //*** search build tree ***
2251 
2252  if ( plInBuildTree() == 1 )
2253  {
2254  plGetName( SOURCE_DIR, "data", fn, &fs );
2255 
2256  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2257  goto done;
2258  }
2259 
2260 //*** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ***
2261 
2262 #if defined ( PLPLOT_LIB_ENV )
2263  if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL )
2264  {
2265  plGetName( dn, "", fn, &fs );
2266 
2267  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2268  goto done;
2269  fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); // what IS set?
2270  }
2271 #endif // PLPLOT_LIB_ENV
2272 
2273 //*** search current directory ***
2274 
2275  if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL )
2276  {
2277  pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn );
2278  free_mem( fs );
2279  return ( file );
2280  }
2281 
2282 //*** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ***
2283 
2284 #if defined ( PLPLOT_HOME_ENV )
2285  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2286  {
2287  plGetName( dn, "lib", fn, &fs );
2288 
2289  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2290  goto done;
2291  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2292  }
2293 #endif // PLPLOT_HOME_ENV/lib
2294 
2295 //*** search installed location ***
2296 
2297 #if defined ( DATA_DIR )
2298  plGetName( DATA_DIR, "", fn, &fs );
2299 
2300  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2301  goto done;
2302 #endif // DATA_DIR
2303 
2304 //*** search hardwired location ***
2305 
2306 #ifdef PLLIBDEV
2307  plGetName( PLLIBDEV, "", fn, &fs );
2308 
2309  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2310  goto done;
2311 #endif // PLLIBDEV
2312 
2313 #ifdef macintosh
2314  file = plMacLibOpen( fn );
2315  if ( file != NULL )
2316  goto done;
2317 #endif // macintosh
2318 
2319  if ( plplotLibDir != NULL )
2320  {
2321  plGetName( plplotLibDir, "", fn, &fs );
2322  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2323  goto done;
2324  }
2325 
2326 //*** not found, give up ***
2327  pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn );
2328  free_mem( fs );
2329  return NULL;
2330 
2331 done:
2332  pldebug( "plLibOpenPdfstr", "Found file %s\n", fs );
2333  free_mem( fs );
2334  return ( file );
2335 }
2336 
2337 //--------------------------------------------------------------------------
2338 // int plFindName
2339 //
2357 //--------------------------------------------------------------------------
2358 
2359 #ifdef __unix
2360 int
2361 plFindName( char *p )
2362 {
2363  ssize_t n;
2364  char buf[PLPLOT_MAX_PATH], *cp;
2365  struct stat sbuf;
2366 
2367  pldebug( "plFindName", "Trying to find %s\n", p );
2368  while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 )
2369  {
2370  pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p );
2371  if ( buf[0] == '/' )
2372  {
2373  // Link is an absolute path
2374 
2375  strncpy( p, buf, (size_t) n );
2376  p[n] = '\0';
2377  pldebug( "plFindName", "Link is absolute: %s\n", p );
2378  }
2379  else
2380  {
2381  // Link is relative to its directory; make it absolute
2382 
2383  cp = 1 + strrchr( p, '/' );
2384  strncpy( cp, buf, (size_t) n );
2385  cp[n] = '\0';
2386  pldebug( "plFindName",
2387  "Link is relative: %s\n\tTotal path:%s\n", cp, p );
2388  }
2389  }
2390 
2391 // This macro not defined on the NEC SX-3
2392 
2393 #ifdef SX
2394 #define S_ISREG( mode ) ( mode & S_IFREG )
2395 #endif
2396 
2397 // SGI machines return ENXIO instead of EINVAL Dubois 11/92
2398 
2399  if ( errno == EINVAL || errno == ENXIO )
2400  {
2401  pldebug( "plFindName", "%s may be the one...\n", p );
2402  if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) )
2403  {
2404  pldebug( "plFindName", "%s is a regular file\n", p );
2405  return ( access( p, X_OK ) );
2406  }
2407  }
2408  pldebug( "plFindName", "%s found but is not executable\n", p );
2409  return ( errno ? errno : -1 );
2410 }
2411 
2412 #else
2413 int
2414 plFindName( char *p )
2415 {
2416  return 1;
2417 }
2418 #endif
2419 
2420 //--------------------------------------------------------------------------
2421 // void plGetName()
2422 //
2432 //--------------------------------------------------------------------------
2433 
2434 void
2435 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec )
2436 {
2437  size_t lfilespec;
2438 
2439 // Malloc space for filespec
2440 
2441  free_mem( *filespec );
2442  lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10;
2443  if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL )
2444  {
2445  plexit( "plGetName: Insufficient memory" );
2446  }
2447 
2448  strcpy( *filespec, dir );
2449 
2450  if ( *subdir != '\0' )
2451  {
2452  strcat_delim( *filespec );
2453  strcat( *filespec, subdir );
2454  }
2455  if ( *filename != '\0' )
2456  {
2457  strcat_delim( *filespec );
2458  strcat( *filespec, filename );
2459  }
2460  pldebug( "plGetName", "Length of full pathname of file to be found is %zu\n", lfilespec );
2461  pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec );
2462 }
2463 
2464 //--------------------------------------------------------------------------
2465 // void strcat_delim()
2466 //
2471 //--------------------------------------------------------------------------
2472 
2473 void
2474 strcat_delim( char *dirspec )
2475 {
2476  size_t ldirspec = strlen( dirspec );
2477 #if defined ( MSDOS ) || defined ( WIN32 )
2478  if ( dirspec[ldirspec - 1] != '\\' )
2479  strcat( dirspec, "\\" );
2480 #elif defined ( macintosh )
2481  if ( dirspec[ldirspec - 1] != ':' )
2482  strcat( dirspec, ":" );
2483 #else // unix is the default
2484  if ( dirspec[ldirspec - 1] != '/' )
2485  strcat( dirspec, "/" );
2486 #endif
2487 }
2488 
2489 //--------------------------------------------------------------------------
2490 // plcol_interp()
2491 //
2500 //--------------------------------------------------------------------------
2501 
2502 void
2503 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
2504 {
2505  PLFLT x, delta;
2506  int il, ir;
2507 
2508  x = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 );
2509  il = (int) x;
2510  ir = il + 1;
2511  delta = x - il;
2512 
2513  if ( ir > pls->ncol1 || il < 0 )
2514  fprintf( stderr, "Invalid color\n" );
2515 
2516  else if ( ir == pls->ncol1 || ( delta == 0. ) )
2517  {
2518  newcolor->r = pls->cmap1[il].r;
2519  newcolor->g = pls->cmap1[il].g;
2520  newcolor->b = pls->cmap1[il].b;
2521  newcolor->a = pls->cmap1[il].a;
2522  }
2523  else
2524  {
2525  newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r );
2526  newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g );
2527  newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b );
2528  newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a;
2529  }
2530 }
2531 
2532 //--------------------------------------------------------------------------
2533 // plOpenFile()
2534 //
2540 //--------------------------------------------------------------------------
2541 
2542 #define MAX_NUM_TRIES 10
2543 void
2545 {
2546  int i = 0, count = 0;
2547  size_t len;
2548  char line[BUFFER_SIZE];
2549 
2550  while ( pls->OutFile == NULL )
2551  {
2552 // Setting pls->FileName = NULL forces creation of a new family member
2553 // You should also free the memory associated with it if you do this
2554 
2555  if ( pls->family && pls->BaseName != NULL )
2556  plP_getmember( pls );
2557 
2558 // Prompt if filename still not known
2559 
2560  if ( pls->FileName == NULL )
2561  {
2562  do
2563  {
2564  fprintf( stdout, "Enter graphics output file name: " );
2565  plio_fgets( line, sizeof ( line ), stdin );
2566  len = strlen( line );
2567  if ( len )
2568  len--;
2569  line[len] = '\0'; // strip new-line
2570  count++; // count zero entries
2571  } while ( !len && count < MAX_NUM_TRIES );
2572  plP_sfnam( pls, line );
2573  }
2574 
2575 // If name is "-", send to stdout
2576 
2577  if ( !strcmp( pls->FileName, "-" ) )
2578  {
2579  pls->OutFile = stdout;
2580  pls->output_type = 1;
2581  break;
2582  }
2583 
2584 // Need this here again, for prompted family initialization
2585 
2586  if ( pls->family && pls->BaseName != NULL )
2587  plP_getmember( pls );
2588 
2589  if ( i++ > 10 )
2590  plexit( "Too many tries." );
2591 
2592  if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
2593  fprintf( stderr, "Can't open %s.\n", pls->FileName );
2594  else
2595  pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
2596  }
2597 }
2598 
2599 //--------------------------------------------------------------------------
2600 // plCloseFile()
2601 //
2605 //--------------------------------------------------------------------------
2606 
2607 void
2609 {
2610  if ( pls->OutFile != NULL )
2611  {
2612  // Don't close if the output file was stdout
2613  if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 )
2614  return;
2615 
2616  fclose( pls->OutFile );
2617  pls->OutFile = NULL;
2618  }
2619 }
2620 
2621 //--------------------------------------------------------------------------
2622 // plP_getmember()
2623 //
2627 //--------------------------------------------------------------------------
2628 
2629 void
2631 {
2632  char tmp[BUFFER_SIZE];
2633  char prefix[BUFFER_SIZE];
2634  char * suffix;
2635  char num[BUFFER_SIZE];
2636  size_t maxlen;
2637 
2638  maxlen = strlen( pls->BaseName ) + 10;
2639  if ( pls->FileName == NULL )
2640  {
2641  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2642  {
2643  plexit( "plP_getmember: Insufficient memory" );
2644  }
2645  }
2646 
2647  suffix = strstr( pls->BaseName, "%n" );
2648 
2649  snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen );
2650  snprintf( num, BUFFER_SIZE, tmp, pls->member );
2651 
2652  if ( suffix == NULL )
2653  snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num );
2654  else
2655  {
2656  strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 );
2657  prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0';
2658  snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 );
2659  }
2660 }
2661 
2662 //--------------------------------------------------------------------------
2663 // plP_sfnam()
2664 //
2670 //--------------------------------------------------------------------------
2671 
2672 void
2673 plP_sfnam( PLStream *pls, const char *fnam )
2674 {
2675  char prefix[BUFFER_SIZE];
2676  char * suffix;
2677  size_t maxlen;
2678  pls->OutFile = NULL;
2679 
2680  if ( pls->FileName != NULL )
2681  free( (void *) pls->FileName );
2682 
2683  maxlen = 10 + strlen( fnam );
2684  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2685  {
2686  plexit( "plP_sfnam: Insufficient memory" );
2687  }
2688 
2689  suffix = strstr( fnam, "%n" );
2690 
2691  if ( suffix == NULL )
2692  {
2693  strncpy( pls->FileName, fnam, maxlen - 1 );
2694  pls->FileName[maxlen - 1] = '\0';
2695  }
2696  else
2697  {
2698  strncpy( prefix, fnam, BUFFER_SIZE - 1 );
2699  prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0';
2700  snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 );
2701  }
2702 
2703  if ( pls->BaseName != NULL )
2704  free( (void *) pls->BaseName );
2705 
2706  if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL )
2707  {
2708  plexit( "plP_sfnam: Insufficient memory" );
2709  }
2710 
2711  strncpy( pls->BaseName, fnam, maxlen - 1 );
2712  pls->BaseName[maxlen - 1] = '\0';
2713 }
2714 
2715 //--------------------------------------------------------------------------
2716 // plFamInit()
2717 //
2721 //--------------------------------------------------------------------------
2722 
2723 void
2725 {
2726  if ( pls->family )
2727  {
2728  pls->bytecnt = 0;
2729  if ( !pls->member )
2730  pls->member = 1;
2731  if ( !pls->finc )
2732  pls->finc = 1;
2733  if ( !pls->fflen )
2734  pls->fflen = 1;
2735  if ( !pls->bytemax )
2736  pls->bytemax = PL_FILESIZE_KB * 1000;
2737  }
2738 }
2739 
2740 //--------------------------------------------------------------------------
2741 // plGetFam()
2742 //
2750 //--------------------------------------------------------------------------
2751 
2752 void
2754 {
2755  PLFLT xpmm_loc, ypmm_loc;
2756  if ( pls->family )
2757  {
2758  if ( pls->bytecnt > pls->bytemax || pls->famadv )
2759  {
2760  PLINT local_page_status = pls->page_status;
2761  plP_tidy();
2762  pls->member += pls->finc;
2763  pls->famadv = 0;
2764  plP_init();
2765  // Restore page status (normally AT_BOP) that was changed
2766  // to AT_EOP by plP_init.
2767  pls->page_status = local_page_status;
2768 
2769  // Apply compensating factor to original xpmm and ypmm so that
2770  // character aspect ratio is preserved when overall aspect ratio
2771  // is changed.
2772  plP_gpixmm( &xpmm_loc, &ypmm_loc );
2773  plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
2774  return;
2775  }
2776  }
2777 }
2778 
2779 //--------------------------------------------------------------------------
2780 // plRotPhy()
2781 //
2794 //--------------------------------------------------------------------------
2795 
2796 void
2798  PLINT *px, PLINT *py )
2799 {
2800  int x, y;
2801 
2802  x = *px;
2803  y = *py;
2804 
2805  switch ( orient % 4 )
2806  {
2807  case 1:
2808  *px = xmin + ( y - ymin );
2809  *py = ymin + ( xmax - x );
2810  break;
2811 
2812  case 2:
2813  *px = xmin + ( xmax - x );
2814  *py = ymin + ( ymax - y );
2815  break;
2816 
2817  case 3:
2818  *px = xmin + ( ymax - y );
2819  *py = ymin + ( x - xmin );
2820  break;
2821 
2822  default:
2823  break; // do nothing
2824  }
2825 }
2826 
2827 //--------------------------------------------------------------------------
2828 // plAllocDev()
2829 //
2836 //--------------------------------------------------------------------------
2837 
2838 PLDev *
2840 {
2841  if ( pls->dev != NULL )
2842  free( (void *) pls->dev );
2843 
2844  pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) );
2845  if ( pls->dev == NULL )
2846  plexit( "plAllocDev: cannot allocate memory\n" );
2847 
2848  return (PLDev *) pls->dev;
2849 }
2850 
2851 //--------------------------------------------------------------------------
2852 // plGinInit()
2853 //
2857 //--------------------------------------------------------------------------
2858 
2859 void
2861 {
2862  gin->type = 0;
2863  gin->state = 0;
2864  gin->keysym = 0;
2865  gin->button = 0;
2866  gin->string[0] = '\0';
2867  gin->pX = gin->pY = -1;
2868  gin->dX = gin->dY = 0.;
2869  gin->wX = gin->wY = 0.;
2870 }
2871 
2872 //--------------------------------------------------------------------------
2873 // plGetInt()
2874 //
2880 //--------------------------------------------------------------------------
2881 
2882 PLINT
2883 plGetInt( const char *s )
2884 {
2885  int m;
2886  int i = 0;
2887  char line[BUFFER_SIZE];
2888 
2889  while ( i++ < 10 )
2890  {
2891  fputs( s, stdout );
2892  plio_fgets( line, sizeof ( line ), stdin );
2893 
2894 #ifdef MSDOS
2895  m = atoi( line );
2896  return ( m );
2897 #else
2898  if ( sscanf( line, "%d", &m ) == 1 )
2899  return ( m );
2900  fprintf( stdout, "No value or value out of range; please try again\n" );
2901 #endif
2902  }
2903  plexit( "Too many tries." );
2904  return ( 0 );
2905 }
2906 
2907 //--------------------------------------------------------------------------
2908 // plGetFlt()
2909 //
2915 //--------------------------------------------------------------------------
2916 
2917 PLFLT
2918 plGetFlt( const char *s )
2919 {
2920  PLFLT m;
2921  double m1;
2922  int i = 0;
2923  char line[BUFFER_SIZE];
2924 
2925  while ( i++ < 10 )
2926  {
2927  fputs( s, stdout );
2928  plio_fgets( line, sizeof ( line ), stdin );
2929 
2930 #ifdef MSDOS
2931  m = atof( line );
2932  return ( m );
2933 #else
2934  if ( sscanf( line, "%lf", &m1 ) == 1 )
2935  {
2936  m = (PLFLT) m1;
2937  return ( m );
2938  }
2939  fprintf( stdout, "No value or value out of range; please try again\n" );
2940 #endif
2941  }
2942  plexit( "Too many tries." );
2943  return ( 0. );
2944 }
2945 
2946 //--------------------------------------------------------------------------
2947 // plstrdup()
2948 //
2955 //--------------------------------------------------------------------------
2956 
2957 char PLDLLIMPEXP *
2958 plstrdup( const char *src )
2959 {
2960  char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) );
2961  if ( dest != NULL )
2962  strcpy( dest, src );
2963  else
2964  plabort( "Out of memory" );
2965 
2966  return dest;
2967 }
2968 
2969 #ifndef PL_HAVE_SNPRINTF
2970 //--------------------------------------------------------------------------
2971 // plsnprintf()
2972 //
2983 //--------------------------------------------------------------------------
2984 
2985 int
2986 plsnprintf( char *buffer, int n, const char *format, ... )
2987 {
2988  int ret;
2989 
2990  va_list args;
2991  va_start( args, format );
2992  ret = vsprintf( buffer, fmt, args );
2993  va_end( argptr );
2994 
2995  // Check if overrun occured
2996  if ( ret > n - 1 )
2997  plabort( "plsnprintf: buffer overrun" );
2998 
2999  return ret;
3000 }
3001 
3002 //--------------------------------------------------------------------------
3003 // plsnscanf()
3004 //
3015 //--------------------------------------------------------------------------
3016 
3017 int
3018 plsnscanf( const char *buffer, int n, const char *format, ... )
3019 {
3020  int ret;
3021 
3022  va_list argptr;
3023  va_start( argptr, format );
3024  ret = vsscanf( buffer, fmt, args );
3025  va_end( argptr );
3026 
3027  return ret;
3028 }
3029 
3030 #endif // PL_HAVE_SNPRINTF
3031 
3032 //--------------------------------------------------------------------------
3033 // plseed()
3034 //
3038 //--------------------------------------------------------------------------
3039 
3040 void
3041 c_plseed( unsigned int s )
3042 {
3043  init_genrand( s );
3044 }
3045 
3046 //--------------------------------------------------------------------------
3047 // plrandd()
3048 //
3051 //--------------------------------------------------------------------------
3052 
3053 PLFLT
3054 c_plrandd( void )
3055 {
3056  return (PLFLT) ( genrand_real1() );
3057 }
3058 
3059 //--------------------------------------------------------------------------
3060 // plsave_set_locale()
3061 //
3071 //--------------------------------------------------------------------------
3072 
3073 char *
3075 {
3076  char * setlocale_ptr;
3077  char * saved_lc_numeric_locale;
3078 
3079  if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) )
3080  {
3081  plexit( "plsave_set_locale: out of memory" );
3082  }
3083 
3084  //save original LC_NUMERIC locale for restore below.
3085  if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) )
3086  {
3087  plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" );
3088  }
3089  strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 );
3090  saved_lc_numeric_locale[99] = '\0';
3091 
3092  // Do not use pldebug since get overflowed stack (infinite recursion)
3093  // if device is interactive (i.e., pls->termin is set).
3094  // comment out fprintf (unless there is some emergency debugging to do)
3095  // because output is too voluminous.
3096  //
3097  // fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3098  //
3099 
3100  if ( !( setlocale( LC_NUMERIC, "C" ) ) )
3101  {
3102  plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" );
3103  }
3104  return saved_lc_numeric_locale;
3105 }
3106 
3107 //--------------------------------------------------------------------------
3108 // plrestore_locale()
3109 //
3115 //--------------------------------------------------------------------------
3116 
3117 void
3118 plrestore_locale( char *saved_lc_numeric_locale )
3119 {
3120  // Do not use pldebug since get overflowed stack (infinite recursion)
3121  // if device is interactive (i.e., pls->termin is set).
3122  // comment out fprintf (unless there is some emergency debugging to do)
3123  // because output is too voluminous.
3124  //
3125  // fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3126  //
3127 
3128  if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
3129  {
3130  char msgbuf[1024];
3131  snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
3132  plexit( msgbuf );
3133  }
3134  free( saved_lc_numeric_locale );
3135 }
3136