PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plctrl.c
Go to the documentation of this file.
1 // $Id: plctrl.c 12966 2014-01-29 00:01:50Z airwin $
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-2013 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
236 c_plscolbga( PLINT r, PLINT g, PLINT b, PLFLT alpha )
237 {
238  plscol0a( 0, r, g, b, alpha );
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
267 c_plgcolbga( PLINT *r, PLINT *g, PLINT *b, PLFLT *alpha )
268 {
269  plgcol0a( 0, r, g, b, alpha );
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 alpha )
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 ) || ( alpha < 0. || alpha > 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) alpha );
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 = alpha;
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 *alpha )
399 {
400  if ( plsc->cmap0 == NULL )
401  plscmap0n( 0 );
402 
403  *r = -1;
404  *g = -1;
405  *b = -1;
406  *alpha = -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  *alpha = 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 *alpha, 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  ( alpha[i] < 0.0 || alpha[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) alpha[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 = alpha[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 *alpha, 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  ( alpha[i] < 0.0 || alpha[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) alpha[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 = alpha[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 *intensity,
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 ( ( intensity[0] != 0 ) || ( intensity[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 = intensity[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  if ( n != npts - 1 )
702  plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
703  else
704  // Note final element is unused, so we set to zero for completeness.
705  plsc->cmap1cp[n].alt_hue_path = 0;
706  }
707 
708 // Calculate and set color map
709 
710  plcmap1_calc();
711 }
712 
713 //--------------------------------------------------------------------------
714 // plscmap1la()
715 //
727 
728 void
729 c_plscmap1la( PLINT itype, PLINT npts, const PLFLT *intensity,
730  const PLFLT *coord1, const PLFLT *coord2, const PLFLT *coord3, const PLFLT *alpha, const PLINT *alt_hue_path )
731 {
732  int n;
733  PLFLT h, l, s, r, g, b;
734 
735  if ( npts < 2 )
736  {
737  plabort( "plscmap1la: Must specify at least two control points" );
738  return;
739  }
740 
741  if ( ( intensity[0] != 0 ) || ( intensity[npts - 1] != 1 ) )
742  {
743  plabort( "plscmap1la: First, last control points must lie on boundary" );
744  return;
745  }
746 
747  if ( npts > PL_MAX_CMAP1CP )
748  {
749  plabort( "plscmap1la: exceeded maximum number of control points" );
750  return;
751  }
752 
753 // Allocate if not done yet
754 
755  if ( plsc->cmap1 == NULL )
756  plscmap1n( 0 );
757 
758 // Save control points
759 
760  plsc->ncp1 = npts;
761 
762  for ( n = 0; n < npts; n++ )
763  {
764  if ( itype == 0 )
765  {
766  h = coord1[n];
767  l = coord2[n];
768  s = coord3[n];
769  }
770  else
771  {
772  r = coord1[n];
773  g = coord2[n];
774  b = coord3[n];
775  c_plrgbhls( r, g, b, &h, &l, &s );
776  }
777 
778  plsc->cmap1cp[n].h = h;
779  plsc->cmap1cp[n].l = l;
780  plsc->cmap1cp[n].s = s;
781  plsc->cmap1cp[n].p = intensity[n];
782  plsc->cmap1cp[n].a = alpha[n];
783 
784  if ( alt_hue_path == NULL )
785  plsc->cmap1cp[n].alt_hue_path = 0;
786  else
787  if ( n != npts - 1 )
788  plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
789  else
790  // Note final element is unused, so we set to zero for completeness.
791  plsc->cmap1cp[n].alt_hue_path = 0;
792  }
793 
794 // Calculate and set color map
795 
796  plcmap1_calc();
797 }
798 
799 //--------------------------------------------------------------------------
800 // plcmap1_calc()
801 //
804 
805 void
807 {
808  int i, n;
809  PLFLT delta, dp, dh, dl, ds, da;
810  PLFLT h, l, s, p, r, g, b, a;
811 
812 // Loop over all control point pairs
813 
814  for ( n = 0; n < plsc->ncp1 - 1; n++ )
815  {
816  if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n + 1].p )
817  continue;
818 
819  // Differences in p, h, l, s between ctrl pts
820 
821  dp = plsc->cmap1cp[n + 1].p - plsc->cmap1cp[n].p;
822  dh = plsc->cmap1cp[n + 1].h - plsc->cmap1cp[n].h;
823  dl = plsc->cmap1cp[n + 1].l - plsc->cmap1cp[n].l;
824  ds = plsc->cmap1cp[n + 1].s - plsc->cmap1cp[n].s;
825  da = plsc->cmap1cp[n + 1].a - plsc->cmap1cp[n].a;
826 
827  // Adjust dh if we are to go around "the back side"
828 
829  if ( plsc->cmap1cp[n].alt_hue_path )
830  dh = ( dh > 0 ) ? dh - 360 : dh + 360;
831 
832  // Loop over all color cells. Only interested in cells located (in
833  // cmap1 space) between n_th and n+1_th control points
834 
835  for ( i = 0; i < plsc->ncol1; i++ )
836  {
837  p = (double) i / ( plsc->ncol1 - 1.0 );
838  if ( ( p < plsc->cmap1cp[n].p ) ||
839  ( p > plsc->cmap1cp[n + 1].p ) )
840  continue;
841 
842  // Interpolate based on position of color cell in cmap1 space
843 
844  delta = ( p - plsc->cmap1cp[n].p ) / dp;
845 
846  // Linearly interpolate to get color cell h, l, s values
847 
848  h = plsc->cmap1cp[n].h + dh * delta;
849  l = plsc->cmap1cp[n].l + dl * delta;
850  s = plsc->cmap1cp[n].s + ds * delta;
851  a = plsc->cmap1cp[n].a + da * delta;
852 
853  while ( h >= 360. )
854  h -= 360.;
855 
856  while ( h < 0. )
857  h += 360.;
858 
859  c_plhlsrgb( h, l, s, &r, &g, &b );
860 
861  plsc->cmap1[i].r = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
862  plsc->cmap1[i].g = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
863  plsc->cmap1[i].b = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
864  plsc->cmap1[i].a = a;
865  }
866  }
867 
868  if ( plsc->level > 0 )
870 }
871 
872 //--------------------------------------------------------------------------
884 //--------------------------------------------------------------------------
885 
886 void
887 c_plscmap1_range( PLFLT min_color, PLFLT max_color )
888 {
889  if ( min_color > max_color || max_color < 0.0 || min_color > 1.0 )
890  {
891  plwarn( "plscmap1_range called with invalid color range" );
892  return;
893  }
894  if ( min_color < 0.0 )
895  {
896  plwarn( "plscmap1_range called with a negative minimum color value" );
897  min_color = 0.0;
898  }
899  if ( max_color > 1.0 )
900  {
901  plwarn( "plscmap1_range called with an out of range maximum color value" );
902  max_color = 1.0;
903  }
904  plsc->cmap1_min = min_color;
905  plsc->cmap1_max = max_color;
906 }
907 
908 //--------------------------------------------------------------------------
913 //--------------------------------------------------------------------------
914 
915 void
916 c_plgcmap1_range( PLFLT *min_color, PLFLT *max_color )
917 {
918  *min_color = plsc->cmap1_min;
919  *max_color = plsc->cmap1_max;
920 }
921 
922 //--------------------------------------------------------------------------
923 // plscmap0n()
924 //
932 
933 void
935 {
936  int ncol, size, imin, imax;
937 
938 // No change
939 
940  if ( ncol0 > 0 && plsc->ncol0 == ncol0 )
941  return;
942 
943 // Handle all possible startup conditions
944 
945  if ( plsc->ncol0 <= 0 && ncol0 <= 0 )
946  ncol = 16;
947  else if ( ncol0 <= 0 )
948  ncol = plsc->ncol0;
949  else
950  ncol = ncol0;
951 
952  imax = ncol - 1;
953  size = ncol * (int) sizeof ( PLColor );
954 
955 // Allocate the space
956 
957  if ( plsc->cmap0 == NULL )
958  {
959  if ( ( plsc->cmap0 = (PLColor *) calloc( 1, (size_t) size ) ) == NULL )
960  {
961  plexit( "c_plscmap0n: Insufficient memory" );
962  }
963  imin = 0;
964  }
965  else
966  {
967  if ( ( plsc->cmap0 = (PLColor *) realloc( plsc->cmap0, (size_t) size ) ) == NULL )
968  {
969  plexit( "c_plscmap0n: Insufficient memory" );
970  }
971  imin = plsc->ncol0;
972  }
973 
974 // Fill in default entries
975 
976  plsc->ncol0 = ncol;
977  plcmap0_def( imin, imax );
978 
979  if ( plsc->level > 0 )
981 }
982 
983 //--------------------------------------------------------------------------
984 // color_set()
985 //
994 
995 void
996 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name )
997 {
998  plsc->cmap0[i].r = r;
999  plsc->cmap0[i].g = g;
1000  plsc->cmap0[i].b = b;
1001  plsc->cmap0[i].a = a;
1002  plsc->cmap0[i].name = name;
1003 }
1004 
1005 #define color_def( i, r, g, b, a, n ) \
1006  if ( i >= imin && i <= imax ) color_set( i, r, g, b, a, n );
1007 
1008 //--------------------------------------------------------------------------
1009 // plcmap0_def()
1010 //
1016 
1017 void
1018 plcmap0_def( int imin, int imax )
1019 {
1020  int i;
1021  unsigned int *r, *g, *b;
1022  double *a;
1023  int number_colors;
1024  if ( imin <= imax )
1025  {
1026  cmap0_palette_read( "", &number_colors, &r, &g, &b, &a );
1027  for ( i = imin; i <= MIN( ( number_colors - 1 ), imax ); i++ )
1028  color_def( i, (U_CHAR) r[i], (U_CHAR) g[i], (U_CHAR) b[i], a[i],
1029  "colors defined by default cmap0 palette file" );
1030  free( r );
1031  free( g );
1032  free( b );
1033  free( a );
1034  }
1035  else
1036  {
1037  number_colors = 0;
1038  }
1039 
1040  // Initialize all colours undefined by the default colour palette file
1041  // to opaque red as a warning.
1042  for ( i = MAX( number_colors, imin ); i <= imax; i++ )
1043  color_def( i, 255, 0, 0, 1.0,
1044  "opaque red colour to mark not defined by palette file" );
1045 }
1046 
1047 //--------------------------------------------------------------------------
1048 // plscmap1n()
1049 //
1057 
1058 void
1060 {
1061  PLINT ncol;
1062  size_t size;
1063 
1064 // No change
1065 
1066  if ( ncol1 > 0 && plsc->ncol1 == ncol1 )
1067  return;
1068 
1069 // Handle all possible startup conditions
1070 
1071  if ( plsc->ncol1 <= 0 && ncol1 <= 0 )
1072  ncol = 128;
1073  else if ( ncol1 <= 0 )
1074  ncol = plsc->ncol1;
1075  else
1076  ncol = ncol1;
1077 
1078  size = (size_t) ncol * sizeof ( PLColor );
1079 
1080 // Allocate the space
1081 
1082  if ( plsc->ncol1 > 0 )
1083  {
1084  if ( ( plsc->cmap1 = (PLColor *) realloc( plsc->cmap1, size ) ) == NULL )
1085  {
1086  plexit( "c_plscmap1n: Insufficient memory" );
1087  }
1088  }
1089  else
1090  {
1091  if ( ( plsc->cmap1 = (PLColor *) calloc( (size_t) ncol, sizeof ( PLColor ) ) ) == NULL )
1092  {
1093  plexit( "c_plscmap1n: Insufficient memory" );
1094  }
1095  }
1096 
1097 // Fill in default entries
1098 
1099  plsc->ncol1 = ncol;
1100  if ( plsc->ncp1 == 0 )
1101  plcmap1_def();
1102  else
1103  plcmap1_calc();
1104 }
1105 
1106 //--------------------------------------------------------------------------
1107 // plcmap1_def()
1108 //
1118 
1119 void
1121 {
1122  PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
1123 
1124 // Positions of control points
1125 
1126  i[0] = 0; // left boundary
1127  i[1] = 0.44; // a little left of center
1128  i[2] = 0.50; // at center
1129  i[3] = 0.50; // at center
1130  i[4] = 0.56; // a little right of center
1131  i[5] = 1; // right boundary
1132 
1133 // For center control points, pick black or white, whichever is closer to bg
1134 // Be careful to pick just short of top or bottom else hue info is lost
1135 
1136  if ( plsc->cmap0 != NULL )
1137  vertex = ( (PLFLT) plsc->cmap0[0].r +
1138  (PLFLT) plsc->cmap0[0].g +
1139  (PLFLT) plsc->cmap0[0].b ) / 3. / 255.;
1140 
1141  if ( vertex < 0.5 )
1142  {
1143  vertex = 0.01;
1144  midpt = 0.10;
1145  }
1146  else
1147  {
1148  vertex = 0.99;
1149  midpt = 0.90;
1150  }
1151 
1152 // Set hue
1153 
1154  h[0] = 260; // low: blue-violet
1155  h[1] = 260; // only change as we go over vertex
1156  h[2] = 260; // only change as we go over vertex
1157  h[3] = 0; // high: red
1158  h[4] = 0; // high: red
1159  h[5] = 0; // keep fixed
1160 
1161 // Set lightness
1162 
1163  l[0] = 0.5; // low
1164  l[1] = midpt; // midpoint value
1165  l[2] = vertex; // bg
1166  l[3] = vertex; // bg
1167  l[4] = midpt; // midpoint value
1168  l[5] = 0.5; // high
1169 
1170 // Set saturation -- keep at maximum
1171 
1172  s[0] = 1;
1173  s[1] = 1;
1174  s[2] = 1;
1175  s[3] = 1;
1176  s[4] = 1;
1177  s[5] = 1;
1178 
1179  c_plscmap1l( 0, 6, i, h, l, s, NULL );
1180 
1181  if ( plsc->level > 0 )
1183 }
1184 
1185 //--------------------------------------------------------------------------
1186 // plscolor()
1187 //
1191 //--------------------------------------------------------------------------
1192 
1193 void
1195 {
1196  plsc->colorset = 1;
1197  plsc->color = color;
1198 }
1199 
1200 //--------------------------------------------------------------------------
1201 // void value()
1202 //
1208 //--------------------------------------------------------------------------
1209 
1210 PLFLT
1211 value( double n1, double n2, double hue )
1212 {
1213  PLFLT val;
1214 
1215  while ( hue >= 360. )
1216  hue -= 360.;
1217  while ( hue < 0. )
1218  hue += 360.;
1219 
1220  if ( hue < 60. )
1221  val = n1 + ( n2 - n1 ) * hue / 60.;
1222  else if ( hue < 180. )
1223  val = n2;
1224  else if ( hue < 240. )
1225  val = n1 + ( n2 - n1 ) * ( 240. - hue ) / 60.;
1226  else
1227  val = n1;
1228 
1229  return ( val );
1230 }
1231 
1232 //--------------------------------------------------------------------------
1233 // void c_plhlsrgb()
1234 //
1251 
1252 void
1253 c_plhlsrgb( PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b )
1254 {
1255  PLFLT m1, m2;
1256 
1257  if ( l <= .5 )
1258  m2 = l * ( s + 1. );
1259  else
1260  m2 = l + s - l * s;
1261 
1262  m1 = 2 * l - m2;
1263 
1264  *p_r = value( m1, m2, h + 120. );
1265  *p_g = value( m1, m2, h );
1266  *p_b = value( m1, m2, h - 120. );
1267 }
1268 
1269 //--------------------------------------------------------------------------
1270 // void c_plrgbhls()
1271 //
1284 
1285 void
1286 c_plrgbhls( PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s )
1287 {
1288  PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
1289 
1290  rgb_min = MIN( r, MIN( g, b ) );
1291  rgb_max = MAX( r, MAX( g, b ) );
1292 
1293  l = ( rgb_min + rgb_max ) / 2.0;
1294 
1295  if ( rgb_min == rgb_max )
1296  {
1297  s = 0;
1298  h = 0;
1299  }
1300  else
1301  {
1302  d = rgb_max - rgb_min;
1303  if ( l < 0.5 )
1304  s = 0.5 * d / l;
1305  else
1306  s = 0.5 * d / ( 1. - l );
1307 
1308  rc = ( rgb_max - r ) / d;
1309  gc = ( rgb_max - g ) / d;
1310  bc = ( rgb_max - b ) / d;
1311 
1312  if ( r == rgb_max )
1313  h = bc - gc;
1314  else if ( g == rgb_max )
1315  h = rc - bc + 2;
1316  else
1317  h = gc - rc - 2;
1318 
1319  h = h * 60;
1320  if ( h < 0 )
1321  h = h + 360;
1322  else if ( h >= 360 )
1323  h = h - 360;
1324  }
1325  *p_h = h;
1326  *p_l = l;
1327  *p_s = s;
1328 }
1329 
1330 //--------------------------------------------------------------------------
1331 // read_line()
1332 //
1342 
1343 static char *
1344 read_line( char *buffer, int length, FILE *fp )
1345 {
1346  char *pchr;
1347 
1348  // Read the string
1349  if ( fgets( buffer, length, fp ) == NULL )
1350  {
1351  return NULL;
1352  }
1353 
1354  // Sanitize the string we read - it may contain EOL characters
1355  // Make sure file reading starts at the next line
1356  pchr = strchr( buffer, '\n' );
1357  if ( pchr != NULL )
1358  {
1359  *pchr = '\0';
1360  }
1361  else
1362  {
1363  if ( fscanf( fp, "%*[^\n]\n" ) == EOF && ferror( fp ) )
1364  {
1365  return NULL;
1366  }
1367  }
1368 
1369 
1370  pchr = strchr( buffer, '\r' );
1371  if ( pchr != NULL )
1372  {
1373  *pchr = '\0';
1374  }
1375 
1376  // Remove trailing blanks
1377  pchr = buffer + strlen( buffer ) - 1;
1378  while ( pchr != buffer && *pchr == ' ' )
1379  {
1380  *pchr = '\0';
1381  pchr--;
1382  }
1383 
1384  return buffer;
1385 }
1386 
1387 //--------------------------------------------------------------------------
1388 // cmap0_palette_read()
1389 //
1399 
1400 void
1401 cmap0_palette_read( const char *filename,
1402  int *number_colors, unsigned int **r, unsigned int **g, unsigned int **b, double **a )
1403 {
1404  int i, err = 0;
1405  char color_info[COLLEN];
1406  char msgbuf[MSGLEN];
1407  FILE *fp;
1408  char * save_locale = plsave_set_locale();
1409 
1410  if ( strlen( filename ) == 0 )
1411  {
1413  if ( fp == NULL )
1414  {
1415  snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
1416  plwarn( msgbuf );
1417  err = 1;
1418  }
1419  }
1420  else
1421  {
1422  fp = plLibOpen( filename );
1423  if ( fp == NULL )
1424  {
1425  snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", filename );
1426  plwarn( msgbuf );
1427  err = 1;
1428  }
1429  }
1430  if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) )
1431  {
1432  fclose( fp );
1433  snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 header\n" );
1434  plwarn( msgbuf );
1435  err = 1;
1436  }
1437 
1438  if ( !err )
1439  {
1440  // Allocate arrays to hold r, g, b, and a data for calling routine.
1441  // The caller must free these after it is finished with them.
1442  if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1443  ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1444  ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1445  ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
1446  {
1447  fclose( fp );
1448  plexit( "cmap0_palette_read: insufficient memory" );
1449  }
1450 
1451  for ( i = 0; i < *number_colors; i++ )
1452  {
1453  if ( read_line( color_info, COLLEN, fp ) == NULL )
1454  {
1455  err = 1;
1456  break;
1457  }
1458 
1459  // Get the color data
1460  if ( strlen( color_info ) == 7 )
1461  {
1462  if ( sscanf( color_info, "#%2x%2x%2x",
1463  (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
1464  (unsigned int *) ( *b + i ) ) != 3 )
1465  {
1466  err = 1;
1467  break;
1468  }
1469  *( *a + i ) = 1.0;
1470  }
1471  else if ( strlen( color_info ) > 9 )
1472  {
1473  if ( sscanf( color_info, "#%2x%2x%2x %lf",
1474  (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
1475  (unsigned int *) ( *b + i ), (double *) ( *a + i ) ) != 4 )
1476  {
1477  err = 1;
1478  break;
1479  }
1480  // fuzzy range check.
1481  if ( *( *a + i ) < -FUZZ_EPSILON || *( *a + i ) > ( 1. + FUZZ_EPSILON ) )
1482  {
1483  err = 1;
1484  break;
1485  }
1486  else if ( *( *a + i ) < 0. )
1487  {
1488  *( *a + i ) = 0.;
1489  }
1490  else if ( *( *a + i ) > 1. )
1491  {
1492  *( *a + i ) = 1.;
1493  }
1494  }
1495  else
1496  {
1497  err = 1;
1498  break;
1499  }
1500  }
1501  fclose( fp );
1502  if ( err )
1503  {
1504  snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 format data line. Line is %s\n",
1505  color_info );
1506  plwarn( msgbuf );
1507  free( *r );
1508  free( *g );
1509  free( *b );
1510  free( *a );
1511  }
1512  }
1513  // Fall back to opaque red on opaque white as visual warning of any
1514  // error above.
1515  if ( err )
1516  {
1517  *number_colors = 16;
1518  if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( int ) ) ) == NULL ) ||
1519  ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1520  ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
1521  ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
1522  {
1523  plexit( "cmap0_palette_read: insufficient memory" );
1524  }
1525  **r = 255;
1526  **g = 255;
1527  **b = 255;
1528  **a = 1.;
1529  for ( i = 1; i < *number_colors; i++ )
1530  {
1531  *( *r + i ) = 255;
1532  *( *g + i ) = 0;
1533  *( *b + i ) = 0;
1534  *( *a + i ) = 1.0;
1535  }
1536  }
1537 
1538  plrestore_locale( save_locale );
1539 }
1540 
1541 //--------------------------------------------------------------------------
1542 // void c_plspal0(filename)
1543 //
1548 
1549 void
1550 c_plspal0( const char *filename )
1551 {
1552  int i;
1553  unsigned int *r, *g, *b;
1554  double *a;
1555  int number_colors;
1556  cmap0_palette_read( filename, &number_colors, &r, &g, &b, &a );
1557  // Allocate default number of cmap0 colours if cmap0 allocation not
1558  // done already.
1559  plscmap0n( 0 );
1560  // Allocate sufficient cmap0 colours to contain present data.
1561  if ( number_colors > plsc->ncol0 )
1562  {
1563  plscmap0n( number_colors );
1564  }
1565  for ( i = 0; i < number_colors; i++ )
1566  {
1567  c_plscol0a( i, (PLINT) r[i], (PLINT) g[i], (PLINT) b[i], a[i] );
1568  }
1569  free( r );
1570  free( g );
1571  free( b );
1572  free( a );
1573 }
1574 
1584 #define fuzzy_range_check( value, min, max, fuzz, err_number ) \
1585  if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) { \
1586  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format data line. Error number is %d. Line is %s\n", err_number, color_info ); \
1587  plwarn( msgbuf ); \
1588  err = 1; \
1589  break; \
1590  } else if ( value < min ) { \
1591  value = min; \
1592  } else if ( value > max ) { \
1593  value = max; \
1594  }
1595 
1596 //--------------------------------------------------------------------------
1597 // void c_plspal1(filename)
1598 //
1604 
1605 void
1606 c_plspal1( const char *filename, PLBOOL interpolate )
1607 {
1608  int i;
1609  int number_colors;
1610  int format_version, err;
1611  PLBOOL rgb;
1612  char color_info[PALLEN];
1613  unsigned int r_i, g_i, b_i;
1614  int pos_i, alt_hue_path_i;
1615  double r_d, g_d, b_d, a_d, pos_d;
1616  PLFLT *r, *g, *b, *a, *pos;
1617  PLINT *ri, *gi, *bi;
1618  PLBOOL *alt_hue_path;
1619  FILE *fp;
1620  char msgbuf[MSGLEN];
1621  char * save_locale = plsave_set_locale();
1622 
1623  rgb = TRUE;
1624  err = 0;
1625  format_version = 0;
1626  if ( strlen( filename ) == 0 )
1627  {
1629  if ( fp == NULL )
1630  {
1631  snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
1632  plwarn( msgbuf );
1633  goto finish;
1634  }
1635  }
1636  else
1637  {
1638  fp = plLibOpen( filename );
1639  if ( fp == NULL )
1640  {
1641  snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", filename );
1642  plwarn( msgbuf );
1643  goto finish;
1644  }
1645  }
1646  // Check for new file format
1647  if ( read_line( color_info, PALLEN, fp ) == NULL )
1648  {
1649  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1650  plwarn( msgbuf );
1651  fclose( fp );
1652  goto finish;
1653  }
1654  if ( strncmp( color_info, "v2 ", 2 ) == 0 )
1655  {
1656  format_version = 1;
1657  if ( strncmp( &color_info[3], "hls", 3 ) == 0 )
1658  rgb = FALSE;
1659  else if ( strncmp( &color_info[3], "rgb", 3 ) == 0 )
1660  rgb = TRUE;
1661  else
1662  {
1663  snprintf( msgbuf, MSGLEN, "Invalid color space %s - assuming RGB\n", &color_info[3] );
1664  plwarn( msgbuf );
1665  rgb = TRUE;
1666  }
1667  if ( read_line( color_info, PALLEN, fp ) == NULL )
1668  {
1669  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1670  plwarn( msgbuf );
1671  fclose( fp );
1672  goto finish;
1673  }
1674  }
1675 
1676  if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 )
1677  {
1678  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
1679  plwarn( msgbuf );
1680  fclose( fp );
1681  goto finish;
1682  }
1683 
1684  r = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1685  g = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1686  b = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1687  ri = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1688  gi = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1689  bi = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
1690  a = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1691  pos = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1692  alt_hue_path = (PLBOOL *) malloc( (size_t) ( number_colors - 1 ) * sizeof ( PLBOOL ) );
1693 
1694  if ( format_version == 0 )
1695  {
1696  int return_sscanf = -1, return_sscanf_old = 0;
1697  // Old tk file format
1698  for ( i = 0; i < number_colors; i++ )
1699  {
1700  if ( read_line( color_info, PALLEN, fp ) == NULL )
1701  {
1702  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1703  plwarn( msgbuf );
1704  fclose( fp );
1705  goto finish;
1706  }
1707  // Ensure string is null terminated if > 160 characters
1708  color_info[PALLEN - 1] = '\0';
1709  return_sscanf = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &alt_hue_path_i );
1710  if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) )
1711  {
1712  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
1713  plwarn( msgbuf );
1714  err = 1;
1715  break;
1716  }
1717  return_sscanf_old = return_sscanf;
1718  // For old format, input colours range from 0 to 255 and
1719  // need to be renormalized to the range from 0. to 1..
1720  r[i] = (PLFLT) r_i / 255.;
1721  g[i] = (PLFLT) g_i / 255.;
1722  b[i] = (PLFLT) b_i / 255.;
1723  a[i] = 1.0;
1724  pos[i] = 0.01 * (PLFLT) pos_i;
1725  fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 1 );
1726  fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 2 );
1727  fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 3 );
1728  fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 4 );
1729  if ( ( return_sscanf == 5 ) && ( i != number_colors - 1 ) )
1730  {
1731  // Next to oldest tk format with alt_hue_path specified.
1732  alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
1733  }
1734  }
1735  if ( return_sscanf == 4 )
1736  {
1737  // Oldest tk format. No alt_hue_path specified.
1738  free( alt_hue_path );
1739  alt_hue_path = NULL;
1740  }
1741  }
1742  else
1743  {
1744  // New floating point file version with support for alpha and alt_hue_path values
1745  for ( i = 0; i < number_colors; i++ )
1746  {
1747  if ( read_line( color_info, PALLEN, fp ) == NULL )
1748  {
1749  snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
1750  plwarn( msgbuf );
1751  fclose( fp );
1752  goto finish;
1753  }
1754  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 )
1755  {
1756  snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
1757  plwarn( msgbuf );
1758  err = 1;
1759  break;
1760  }
1761 
1762  r[i] = (PLFLT) r_d;
1763  g[i] = (PLFLT) g_d;
1764  b[i] = (PLFLT) b_d;
1765  a[i] = (PLFLT) a_d;
1766  pos[i] = (PLFLT) pos_d;
1767  // Check that all rgba and pos data within range from 0. to
1768  // 1. except for the hls colour space case where the first
1769  // coordinate is checked within range from 0. to 360.
1770  if ( rgb )
1771  {
1772  fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 5 );
1773  }
1774  else
1775  {
1776  fuzzy_range_check( r[i], 0., 360., ( 360. * FUZZ_EPSILON ), 6 );
1777  }
1778  fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 7 );
1779  fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 8 );
1780  fuzzy_range_check( a[i], 0., 1., FUZZ_EPSILON, 9 );
1781  fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 10 );
1782 
1783  if ( i != number_colors - 1 )
1784  alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
1785  }
1786  }
1787  fclose( fp );
1788 
1789  if ( !err )
1790  {
1791  if ( interpolate )
1792  {
1793  c_plscmap1la( rgb, number_colors, pos, r, g, b, a, alt_hue_path );
1794  }
1795  else
1796  {
1797  for ( i = 0; i < number_colors; i++ )
1798  {
1799  ri[i] = (PLINT) ( r[i] * 255.0 );
1800  gi[i] = (PLINT) ( g[i] * 255.0 );
1801  bi[i] = (PLINT) ( b[i] * 255.0 );
1802  }
1803  c_plscmap1a( ri, gi, bi, a, number_colors );
1804  }
1805  }
1806  else
1807  {
1808  // Fall back to red scale as visual warning if some problem occurred
1809  // above.
1810  free( r );
1811  free( g );
1812  free( b );
1813  free( pos );
1814  number_colors = 2;
1815  r = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1816  g = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1817  b = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1818  pos = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
1819  r[0] = 0.;
1820  r[1] = 1.;
1821  g[0] = 0.;
1822  g[1] = 0.;
1823  b[0] = 0.;
1824  b[1] = 0.;
1825  pos[0] = 0.;
1826  pos[1] = 1.;
1827  c_plscmap1l( TRUE, number_colors, pos, r, g, b, NULL );
1828  }
1829 
1830  free( r );
1831  free( g );
1832  free( b );
1833  free( ri );
1834  free( gi );
1835  free( bi );
1836  free( a );
1837  free( pos );
1838  free( alt_hue_path );
1839 
1840 finish: plrestore_locale( save_locale );
1841 }
1842 
1843 //--------------------------------------------------------------------------
1844 // A grab-bag of various control routines.
1845 //--------------------------------------------------------------------------
1846 
1847 //--------------------------------------------------------------------------
1848 // void plwarn()
1849 //
1853 
1854 void
1855 plwarn( const char *errormsg )
1856 {
1857  int was_gfx = 0;
1858 
1859  if ( plsc->graphx == 1 )
1860  {
1861  was_gfx = 1;
1862  pltext();
1863  }
1864 
1865  fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
1866  if ( *errormsg != '\0' )
1867  fprintf( stderr, "%s\n", errormsg );
1868 
1869  if ( was_gfx == 1 )
1870  plgra();
1871 }
1872 
1873 //--------------------------------------------------------------------------
1874 // void plabort()
1875 //
1884 
1885 void
1886 plabort( const char *errormsg )
1887 {
1888  if ( abort_handler != NULL )
1889  ( *abort_handler )( errormsg );
1890 
1891  if ( plsc->errcode != NULL )
1892  *( plsc->errcode ) = 1;
1893 
1894  if ( plsc->errmsg != NULL )
1895  {
1896  sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
1897  if ( *errormsg != '\0' )
1898  sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg );
1899  }
1900  else
1901  {
1902  int was_gfx = 0;
1903 
1904  if ( plsc->graphx == 1 )
1905  {
1906  was_gfx = 1;
1907  pltext();
1908  }
1909 
1910  fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
1911  if ( *errormsg != '\0' )
1912  fprintf( stderr, "%s, aborting operation\n", errormsg );
1913 
1914  if ( was_gfx == 1 )
1915  plgra();
1916  }
1917 }
1918 
1919 
1920 //--------------------------------------------------------------------------
1921 // void plsabort()
1922 //
1927 //--------------------------------------------------------------------------
1928 
1929 void
1930 plsabort( void ( *handler )( const char * ) )
1931 {
1932  abort_handler = handler;
1933 }
1934 
1935 //--------------------------------------------------------------------------
1936 // void plexit()
1937 //
1947 //--------------------------------------------------------------------------
1948 
1949 void
1950 plexit( const char *errormsg )
1951 {
1952  int status = 1;
1953 
1954  if ( exit_handler != NULL )
1955  status = ( *exit_handler )( errormsg );
1956 
1957  plsc->nopause = 1;
1958  if ( *errormsg != '\0' )
1959  {
1960  fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
1961  fprintf( stderr, "%s\n", errormsg );
1962  }
1963  plend();
1964 
1965  fprintf( stderr, "Program aborted\n" );
1966  exit( status );
1967 }
1968 
1969 //--------------------------------------------------------------------------
1970 // void plsexit()
1971 //
1976 //--------------------------------------------------------------------------
1977 
1978 void
1979 plsexit( int ( *handler )( const char * ) )
1980 {
1981  exit_handler = handler;
1982 }
1983 
1984 //--------------------------------------------------------------------------
1985 // void plgra()
1986 //
1992 //--------------------------------------------------------------------------
1993 
1994 void
1995 c_plgra( void )
1996 {
1997  if ( plsc->level > 0 )
1998  plP_esc( PLESC_GRAPH, NULL );
1999 }
2000 
2001 //--------------------------------------------------------------------------
2002 // void plxormod()
2003 //
2008 
2009 void
2010 c_plxormod( PLINT mode, PLINT *status ) // xor mode
2011 {
2012  static int ostate = 0;
2013 
2014  if ( !plsc->dev_xor )
2015  {
2016  *status = 0;
2017  return;
2018  }
2019 
2020  if ( plsc->level > 0 )
2021  {
2022  plP_esc( PLESC_XORMOD, &mode );
2023  if ( mode )
2024  {
2025  ostate = plsc->plbuf_write;
2026  plsc->plbuf_write = 0;
2027  }
2028  else
2029  plsc->plbuf_write = ostate;
2030  }
2031  *status = 1;
2032 }
2033 
2034 //--------------------------------------------------------------------------
2039 void
2041 {
2042  if ( !plsc->dev_modeset )
2043  {
2044  plwarn( "plsdrawmode: Mode setting is not supported by this device" );
2045  }
2046  else if ( plsc->level > 0 )
2047  {
2048  plP_esc( PLESC_MODESET, &mode );
2049  }
2050  else
2051  {
2052  plwarn( "plsdrawmode: Initialize PLplot first" );
2053  }
2054  return;
2055 }
2056 
2057 //--------------------------------------------------------------------------
2062 PLINT
2064 {
2065  PLINT mode;
2066 
2067  if ( !plsc->dev_modeset )
2068  {
2069  plwarn( "plgdrawmode: Mode getting is not supported by this device" );
2070  mode = PL_DRAWMODE_UNKNOWN;
2071  }
2072  else if ( plsc->level > 0 )
2073  {
2074  plP_esc( PLESC_MODEGET, &mode );
2075  }
2076  else
2077  {
2078  plwarn( "plsdrawmode: Initialize PLplot first" );
2079  mode = PL_DRAWMODE_UNKNOWN;
2080  }
2081 
2082  return ( mode );
2083 }
2084 
2085 //--------------------------------------------------------------------------
2086 // void pltext()
2087 //
2089 //--------------------------------------------------------------------------
2090 
2091 void
2092 c_pltext( void )
2093 {
2094  if ( plsc->level > 0 )
2095  plP_esc( PLESC_TEXT, NULL );
2096 }
2097 
2098 //--------------------------------------------------------------------------
2099 // void pl_cmd()
2100 //
2107 //--------------------------------------------------------------------------
2108 
2109 void
2110 pl_cmd( PLINT op, void *ptr )
2111 {
2112  plP_esc( op, ptr );
2113 }
2114 
2115 //--------------------------------------------------------------------------
2116 // char *plFindCommand
2117 //
2134 //--------------------------------------------------------------------------
2135 
2136 char *
2137 plFindCommand( const char *fn )
2138 {
2139  char *fs = NULL, *dn;
2140 
2141  //*** see if in build tree **
2142  if ( plInBuildTree() == 1 )
2143  {
2144  plGetName( BUILD_DIR, "bindings/tk", fn, &fs );
2145  if ( !plFindName( fs ) )
2146  return fs;
2147  else
2148  {
2149  plGetName( SOURCE_DIR, "scripts", fn, &fs );
2150  if ( !plFindName( fs ) )
2151  return fs;
2152  }
2153  }
2154 
2155 // PLPLOT_BIN_ENV = $(PLPLOT_BIN)
2156 
2157 #if defined ( PLPLOT_BIN_ENV )
2158  if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL )
2159  {
2160  plGetName( dn, "", fn, &fs );
2161  if ( !plFindName( fs ) )
2162  return fs;
2163  fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); // what IS set?
2164  }
2165 #endif // PLPLOT_BIN_ENV
2166 
2167 // Current directory
2168 
2169  plGetName( ".", "", fn, &fs );
2170  if ( !plFindName( fs ) )
2171  return fs;
2172 
2173 // PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
2174 
2175 #if defined ( PLPLOT_HOME_ENV )
2176  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2177  {
2178  plGetName( dn, "bin", fn, &fs );
2179  if ( !plFindName( fs ) )
2180  return fs;
2181  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2182  }
2183 #endif // PLPLOT_HOME_ENV
2184 
2185 // BIN_DIR
2186 
2187 #if defined ( BIN_DIR )
2188  plGetName( BIN_DIR, "", fn, &fs );
2189  if ( !plFindName( fs ) )
2190  return fs;
2191 #endif
2192 
2193 // Crapped out
2194 
2195  free_mem( fs );
2196  fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn );
2197 #if defined ( BIN_DIR )
2198  fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" ); // what WAS set?
2199 #endif // BIN_DIR
2200  return NULL;
2201 }
2202 
2203 //--------------------------------------------------------------------------
2204 // FILE *plLibOpen(fn)
2205 //
2217 //--------------------------------------------------------------------------
2218 
2219 FILE *
2220 plLibOpen( const char *fn )
2221 {
2222  FILE *ret = NULL;
2223 
2224  PDFstrm *pdfs = plLibOpenPdfstrm( fn );
2225  if ( pdfs == NULL )
2226  {
2227  return NULL;
2228  }
2229  if ( pdfs->file != NULL )
2230  {
2231  ret = pdfs->file;
2232  pdfs->file = NULL;
2233  }
2234  pdf_close( pdfs );
2235  return ret;
2236 }
2237 
2238 //--------------------------------------------------------------------------
2239 // FILE *plLibOpenPdfstrm(fn)
2240 //
2252 //--------------------------------------------------------------------------
2253 PDFstrm *
2254 plLibOpenPdfstrm( const char *fn )
2255 {
2256  PDFstrm *file;
2257  char *fs = NULL, *dn = NULL;
2258 
2259 //*** search build tree ***
2260 
2261  if ( plInBuildTree() == 1 )
2262  {
2263  plGetName( SOURCE_DIR, "data", fn, &fs );
2264 
2265  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2266  goto done;
2267  }
2268 
2269 //*** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ***
2270 
2271 #if defined ( PLPLOT_LIB_ENV )
2272  if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL )
2273  {
2274  plGetName( dn, "", fn, &fs );
2275 
2276  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2277  goto done;
2278  fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); // what IS set?
2279  }
2280 #endif // PLPLOT_LIB_ENV
2281 
2282 //*** search current directory ***
2283 
2284  if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL )
2285  {
2286  pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn );
2287  free_mem( fs );
2288  return ( file );
2289  }
2290 
2291 //*** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ***
2292 
2293 #if defined ( PLPLOT_HOME_ENV )
2294  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2295  {
2296  plGetName( dn, "lib", fn, &fs );
2297 
2298  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2299  goto done;
2300  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2301  }
2302 #endif // PLPLOT_HOME_ENV/lib
2303 
2304 //*** search installed location ***
2305 
2306 #if defined ( DATA_DIR )
2307  plGetName( DATA_DIR, "", fn, &fs );
2308 
2309  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2310  goto done;
2311 #endif // DATA_DIR
2312 
2313 //*** search hardwired location ***
2314 
2315 #ifdef PLLIBDEV
2316  plGetName( PLLIBDEV, "", fn, &fs );
2317 
2318  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2319  goto done;
2320 #endif // PLLIBDEV
2321 
2322 #ifdef macintosh
2323  file = plMacLibOpen( fn );
2324  if ( file != NULL )
2325  goto done;
2326 #endif // macintosh
2327 
2328  if ( plplotLibDir != NULL )
2329  {
2330  plGetName( plplotLibDir, "", fn, &fs );
2331  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2332  goto done;
2333  }
2334 
2335 //*** not found, give up ***
2336  pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn );
2337  free_mem( fs );
2338  return NULL;
2339 
2340 done:
2341  pldebug( "plLibOpenPdfstr", "Found file %s\n", fs );
2342  free_mem( fs );
2343  return ( file );
2344 }
2345 
2346 //--------------------------------------------------------------------------
2347 // int plFindName
2348 //
2366 //--------------------------------------------------------------------------
2367 
2368 #ifdef __unix
2369 int
2370 plFindName( char *p )
2371 {
2372  ssize_t n;
2373  char buf[PLPLOT_MAX_PATH], *cp;
2374  struct stat sbuf;
2375 
2376  pldebug( "plFindName", "Trying to find %s\n", p );
2377  while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 )
2378  {
2379  pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p );
2380  if ( buf[0] == '/' )
2381  {
2382  // Link is an absolute path
2383 
2384  strncpy( p, buf, (size_t) n );
2385  p[n] = '\0';
2386  pldebug( "plFindName", "Link is absolute: %s\n", p );
2387  }
2388  else
2389  {
2390  // Link is relative to its directory; make it absolute
2391 
2392  cp = 1 + strrchr( p, '/' );
2393  strncpy( cp, buf, (size_t) n );
2394  cp[n] = '\0';
2395  pldebug( "plFindName",
2396  "Link is relative: %s\n\tTotal path:%s\n", cp, p );
2397  }
2398  }
2399 
2400 // This macro not defined on the NEC SX-3
2401 
2402 #ifdef SX
2403 #define S_ISREG( mode ) ( mode & S_IFREG )
2404 #endif
2405 
2406 // SGI machines return ENXIO instead of EINVAL Dubois 11/92
2407 
2408  if ( errno == EINVAL || errno == ENXIO )
2409  {
2410  pldebug( "plFindName", "%s may be the one...\n", p );
2411  if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) )
2412  {
2413  pldebug( "plFindName", "%s is a regular file\n", p );
2414  return ( access( p, X_OK ) );
2415  }
2416  }
2417  pldebug( "plFindName", "%s found but is not executable\n", p );
2418  return ( errno ? errno : -1 );
2419 }
2420 
2421 #else
2422 int
2423 plFindName( char *p )
2424 {
2425  return 1;
2426 }
2427 #endif
2428 
2429 //--------------------------------------------------------------------------
2430 // void plGetName()
2431 //
2441 //--------------------------------------------------------------------------
2442 
2443 void
2444 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec )
2445 {
2446  size_t lfilespec;
2447 
2448 // Malloc space for filespec
2449 
2450  free_mem( *filespec );
2451  // Be slightly generous since 3 (two delimiters + NULL byte) should be
2452  // enough.
2453  lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10;
2454  if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL )
2455  {
2456  plexit( "plGetName: Insufficient memory" );
2457  }
2458 
2459  strcpy( *filespec, dir );
2460 
2461  if ( *subdir != '\0' )
2462  {
2463  strcat_delim( *filespec );
2464  strcat( *filespec, subdir );
2465  }
2466  if ( *filename != '\0' )
2467  {
2468  strcat_delim( *filespec );
2469  strcat( *filespec, filename );
2470  }
2471  pldebug( "plGetName", "Maximum length of full pathname of file to be found is %zu\n", lfilespec - 1 );
2472  pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec );
2473 }
2474 
2475 //--------------------------------------------------------------------------
2476 // void strcat_delim()
2477 //
2482 //--------------------------------------------------------------------------
2483 
2484 void
2485 strcat_delim( char *dirspec )
2486 {
2487  size_t ldirspec = strlen( dirspec );
2488 #if defined ( MSDOS ) || defined ( WIN32 )
2489  if ( dirspec[ldirspec - 1] != '\\' )
2490  strcat( dirspec, "\\" );
2491 #elif defined ( macintosh )
2492  if ( dirspec[ldirspec - 1] != ':' )
2493  strcat( dirspec, ":" );
2494 #else // unix is the default
2495  if ( dirspec[ldirspec - 1] != '/' )
2496  strcat( dirspec, "/" );
2497 #endif
2498 }
2499 
2500 //--------------------------------------------------------------------------
2501 // plcol_interp()
2502 //
2511 //--------------------------------------------------------------------------
2512 
2513 void
2514 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
2515 {
2516  PLFLT x, delta;
2517  int il, ir;
2518 
2519  x = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 );
2520  il = (int) x;
2521  ir = il + 1;
2522  delta = x - il;
2523 
2524  if ( ir > pls->ncol1 || il < 0 )
2525  fprintf( stderr, "Invalid color\n" );
2526 
2527  else if ( ir == pls->ncol1 || ( delta == 0. ) )
2528  {
2529  newcolor->r = pls->cmap1[il].r;
2530  newcolor->g = pls->cmap1[il].g;
2531  newcolor->b = pls->cmap1[il].b;
2532  newcolor->a = pls->cmap1[il].a;
2533  }
2534  else
2535  {
2536  newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r );
2537  newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g );
2538  newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b );
2539  newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a;
2540  }
2541 }
2542 
2543 //--------------------------------------------------------------------------
2544 // plOpenFile()
2545 //
2551 //--------------------------------------------------------------------------
2552 
2553 #define MAX_NUM_TRIES 10
2554 void
2556 {
2557  int i = 0, count = 0;
2558  size_t len;
2559  char line[BUFFER_SIZE];
2560 
2561  while ( pls->OutFile == NULL )
2562  {
2563 // Setting pls->FileName = NULL forces creation of a new family member
2564 // You should also free the memory associated with it if you do this
2565 
2566  if ( pls->family && pls->BaseName != NULL )
2567  plP_getmember( pls );
2568 
2569 // Prompt if filename still not known
2570 
2571  if ( pls->FileName == NULL )
2572  {
2573  do
2574  {
2575  fprintf( stdout, "Enter graphics output file name: " );
2576  plio_fgets( line, sizeof ( line ), stdin );
2577  len = strlen( line );
2578  if ( len )
2579  len--;
2580  line[len] = '\0'; // strip new-line
2581  count++; // count zero entries
2582  } while ( !len && count < MAX_NUM_TRIES );
2583  plP_sfnam( pls, line );
2584  }
2585 
2586 // If name is "-", send to stdout
2587 
2588  if ( !strcmp( pls->FileName, "-" ) )
2589  {
2590  pls->OutFile = stdout;
2591  pls->output_type = 1;
2592  break;
2593  }
2594 
2595 // Need this here again, for prompted family initialization
2596 
2597  if ( pls->family && pls->BaseName != NULL )
2598  plP_getmember( pls );
2599 
2600  if ( i++ > 10 )
2601  plexit( "Too many tries." );
2602 
2603  if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
2604  fprintf( stderr, "Can't open %s.\n", pls->FileName );
2605  else
2606  pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
2607  }
2608 }
2609 
2610 //--------------------------------------------------------------------------
2611 // plCloseFile()
2612 //
2616 //--------------------------------------------------------------------------
2617 
2618 void
2620 {
2621  if ( pls->OutFile != NULL )
2622  {
2623  // Don't close if the output file was stdout
2624  if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 )
2625  return;
2626 
2627  fclose( pls->OutFile );
2628  pls->OutFile = NULL;
2629  }
2630 }
2631 
2632 //--------------------------------------------------------------------------
2633 // plP_getmember()
2634 //
2638 //--------------------------------------------------------------------------
2639 
2640 void
2642 {
2643  char tmp[BUFFER_SIZE];
2644  char prefix[BUFFER_SIZE];
2645  char * suffix;
2646  char num[BUFFER_SIZE];
2647  size_t maxlen;
2648 
2649  maxlen = strlen( pls->BaseName ) + 10;
2650  if ( pls->FileName == NULL )
2651  {
2652  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2653  {
2654  plexit( "plP_getmember: Insufficient memory" );
2655  }
2656  }
2657 
2658  suffix = strstr( pls->BaseName, "%n" );
2659 
2660  snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen );
2661  snprintf( num, BUFFER_SIZE, tmp, pls->member );
2662 
2663  if ( suffix == NULL )
2664  snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num );
2665  else
2666  {
2667  strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 );
2668  prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0';
2669  snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 );
2670  }
2671 }
2672 
2673 //--------------------------------------------------------------------------
2674 // plP_sfnam()
2675 //
2681 //--------------------------------------------------------------------------
2682 
2683 void
2684 plP_sfnam( PLStream *pls, const char *fnam )
2685 {
2686  char prefix[BUFFER_SIZE];
2687  char * suffix;
2688  size_t maxlen;
2689  pls->OutFile = NULL;
2690 
2691  if ( pls->FileName != NULL )
2692  free( (void *) pls->FileName );
2693 
2694  maxlen = 10 + strlen( fnam );
2695  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2696  {
2697  plexit( "plP_sfnam: Insufficient memory" );
2698  }
2699 
2700  suffix = strstr( fnam, "%n" );
2701 
2702  if ( suffix == NULL )
2703  {
2704  strncpy( pls->FileName, fnam, maxlen - 1 );
2705  pls->FileName[maxlen - 1] = '\0';
2706  }
2707  else
2708  {
2709  strncpy( prefix, fnam, BUFFER_SIZE - 1 );
2710  prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0';
2711  snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 );
2712  }
2713 
2714  if ( pls->BaseName != NULL )
2715  free( (void *) pls->BaseName );
2716 
2717  if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL )
2718  {
2719  plexit( "plP_sfnam: Insufficient memory" );
2720  }
2721 
2722  strncpy( pls->BaseName, fnam, maxlen - 1 );
2723  pls->BaseName[maxlen - 1] = '\0';
2724 }
2725 
2726 //--------------------------------------------------------------------------
2727 // plFamInit()
2728 //
2732 //--------------------------------------------------------------------------
2733 
2734 void
2736 {
2737  if ( pls->family )
2738  {
2739  pls->bytecnt = 0;
2740  if ( !pls->member )
2741  pls->member = 1;
2742  if ( !pls->finc )
2743  pls->finc = 1;
2744  if ( !pls->fflen )
2745  pls->fflen = 1;
2746  if ( !pls->bytemax )
2747  pls->bytemax = PL_FILESIZE_KB * 1000;
2748  }
2749 }
2750 
2751 //--------------------------------------------------------------------------
2752 // plGetFam()
2753 //
2761 //--------------------------------------------------------------------------
2762 
2763 void
2765 {
2766  PLFLT xpmm_loc, ypmm_loc;
2767  if ( pls->family )
2768  {
2769  if ( pls->bytecnt > pls->bytemax || pls->famadv )
2770  {
2771  PLINT local_page_status = pls->page_status;
2772  plP_tidy();
2773  pls->member += pls->finc;
2774  pls->famadv = 0;
2775  plP_init();
2776  // Restore page status (normally AT_BOP) that was changed
2777  // to AT_EOP by plP_init.
2778  pls->page_status = local_page_status;
2779 
2780  // Apply compensating factor to original xpmm and ypmm so that
2781  // character aspect ratio is preserved when overall aspect ratio
2782  // is changed.
2783  plP_gpixmm( &xpmm_loc, &ypmm_loc );
2784  plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
2785  return;
2786  }
2787  }
2788 }
2789 
2790 //--------------------------------------------------------------------------
2791 // plRotPhy()
2792 //
2805 //--------------------------------------------------------------------------
2806 
2807 void
2809  PLINT *px, PLINT *py )
2810 {
2811  int x, y;
2812 
2813  x = *px;
2814  y = *py;
2815 
2816  switch ( orient % 4 )
2817  {
2818  case 1:
2819  *px = xmin + ( y - ymin );
2820  *py = ymin + ( xmax - x );
2821  break;
2822 
2823  case 2:
2824  *px = xmin + ( xmax - x );
2825  *py = ymin + ( ymax - y );
2826  break;
2827 
2828  case 3:
2829  *px = xmin + ( ymax - y );
2830  *py = ymin + ( x - xmin );
2831  break;
2832 
2833  default:
2834  break; // do nothing
2835  }
2836 }
2837 
2838 //--------------------------------------------------------------------------
2839 // plAllocDev()
2840 //
2847 //--------------------------------------------------------------------------
2848 
2849 PLDev *
2851 {
2852  if ( pls->dev != NULL )
2853  free( (void *) pls->dev );
2854 
2855  pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) );
2856  if ( pls->dev == NULL )
2857  plexit( "plAllocDev: cannot allocate memory\n" );
2858 
2859  return (PLDev *) pls->dev;
2860 }
2861 
2862 //--------------------------------------------------------------------------
2863 // plGinInit()
2864 //
2868 //--------------------------------------------------------------------------
2869 
2870 void
2872 {
2873  gin->type = 0;
2874  gin->state = 0;
2875  gin->keysym = 0;
2876  gin->button = 0;
2877  gin->string[0] = '\0';
2878  gin->pX = gin->pY = -1;
2879  gin->dX = gin->dY = 0.;
2880  gin->wX = gin->wY = 0.;
2881 }
2882 
2883 //--------------------------------------------------------------------------
2884 // plGetInt()
2885 //
2891 //--------------------------------------------------------------------------
2892 
2893 PLINT
2894 plGetInt( const char *s )
2895 {
2896  int m;
2897  int i = 0;
2898  char line[BUFFER_SIZE];
2899 
2900  while ( i++ < 10 )
2901  {
2902  fputs( s, stdout );
2903  plio_fgets( line, sizeof ( line ), stdin );
2904 
2905 #ifdef MSDOS
2906  m = atoi( line );
2907  return ( m );
2908 #else
2909  if ( sscanf( line, "%d", &m ) == 1 )
2910  return ( m );
2911  fprintf( stdout, "No value or value out of range; please try again\n" );
2912 #endif
2913  }
2914  plexit( "Too many tries." );
2915  return ( 0 );
2916 }
2917 
2918 //--------------------------------------------------------------------------
2919 // plGetFlt()
2920 //
2926 //--------------------------------------------------------------------------
2927 
2928 PLFLT
2929 plGetFlt( const char *s )
2930 {
2931  PLFLT m;
2932  double m1;
2933  int i = 0;
2934  char line[BUFFER_SIZE];
2935 
2936  while ( i++ < 10 )
2937  {
2938  fputs( s, stdout );
2939  plio_fgets( line, sizeof ( line ), stdin );
2940 
2941 #ifdef MSDOS
2942  m = atof( line );
2943  return ( m );
2944 #else
2945  if ( sscanf( line, "%lf", &m1 ) == 1 )
2946  {
2947  m = (PLFLT) m1;
2948  return ( m );
2949  }
2950  fprintf( stdout, "No value or value out of range; please try again\n" );
2951 #endif
2952  }
2953  plexit( "Too many tries." );
2954  return ( 0. );
2955 }
2956 
2957 //--------------------------------------------------------------------------
2958 // plstrdup()
2959 //
2966 //--------------------------------------------------------------------------
2967 
2968 char PLDLLIMPEXP *
2969 plstrdup( const char *src )
2970 {
2971  char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) );
2972  if ( dest != NULL )
2973  strcpy( dest, src );
2974  else
2975  plabort( "Out of memory" );
2976 
2977  return dest;
2978 }
2979 
2980 #ifndef PL_HAVE_SNPRINTF
2981 //--------------------------------------------------------------------------
2982 // plsnprintf()
2983 //
2994 //--------------------------------------------------------------------------
2995 
2996 int
2997 plsnprintf( char *buffer, int n, const char *format, ... )
2998 {
2999  int ret;
3000 
3001  va_list args;
3002  va_start( args, format );
3003  ret = vsprintf( buffer, format, args );
3004  va_end( args );
3005 
3006  // Check if overrun occured
3007  if ( ret > n - 1 )
3008  plabort( "plsnprintf: buffer overrun" );
3009 
3010  return ret;
3011 }
3012 
3013 //--------------------------------------------------------------------------
3014 // plsnscanf()
3015 //
3026 //--------------------------------------------------------------------------
3027 
3028 int
3029 plsnscanf( const char *buffer, int n, const char *format, ... )
3030 {
3031  int ret;
3032 
3033  va_list args;
3034  va_start( args, format );
3035  ret = vsscanf( buffer, format, args );
3036  va_end( args );
3037 
3038  return ret;
3039 }
3040 
3041 #endif // PL_HAVE_SNPRINTF
3042 
3043 //--------------------------------------------------------------------------
3044 // plseed()
3045 //
3049 //--------------------------------------------------------------------------
3050 
3051 void
3052 c_plseed( unsigned int seed )
3053 {
3054  init_genrand( seed );
3055 }
3056 
3057 //--------------------------------------------------------------------------
3058 // plrandd()
3059 //
3062 //--------------------------------------------------------------------------
3063 
3064 PLFLT
3065 c_plrandd( void )
3066 {
3067  return (PLFLT) ( genrand_real1() );
3068 }
3069 
3070 //--------------------------------------------------------------------------
3071 // plsave_set_locale()
3072 //
3082 //--------------------------------------------------------------------------
3083 
3084 char *
3086 {
3087  char * setlocale_ptr;
3088  char * saved_lc_numeric_locale;
3089 
3090  if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) )
3091  {
3092  plexit( "plsave_set_locale: out of memory" );
3093  }
3094 
3095  //save original LC_NUMERIC locale for restore below.
3096  if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) )
3097  {
3098  plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" );
3099  }
3100  strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 );
3101  saved_lc_numeric_locale[99] = '\0';
3102 
3103  // Do not use pldebug since get overflowed stack (infinite recursion)
3104  // if device is interactive (i.e., pls->termin is set).
3105  // comment out fprintf (unless there is some emergency debugging to do)
3106  // because output is too voluminous.
3107  //
3108  // fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3109  //
3110 
3111  if ( !( setlocale( LC_NUMERIC, "C" ) ) )
3112  {
3113  plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" );
3114  }
3115  return saved_lc_numeric_locale;
3116 }
3117 
3118 //--------------------------------------------------------------------------
3119 // plrestore_locale()
3120 //
3126 //--------------------------------------------------------------------------
3127 
3128 void
3129 plrestore_locale( char *saved_lc_numeric_locale )
3130 {
3131  // Do not use pldebug since get overflowed stack (infinite recursion)
3132  // if device is interactive (i.e., pls->termin is set).
3133  // comment out fprintf (unless there is some emergency debugging to do)
3134  // because output is too voluminous.
3135  //
3136  // fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3137  //
3138 
3139  if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
3140  {
3141  char msgbuf[1024];
3142  snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
3143  plexit( msgbuf );
3144  }
3145  free( saved_lc_numeric_locale );
3146 }
3147