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