PLplot  5.11.1
 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  if ( plsc->level > 0 )
2111  plP_esc( op, ptr );
2112 }
2113 
2114 //--------------------------------------------------------------------------
2115 // char *plFindCommand
2116 //
2133 //--------------------------------------------------------------------------
2134 
2135 char *
2136 plFindCommand( const char *fn )
2137 {
2138  char *fs = NULL, *dn;
2139 
2140  //*** see if in build tree **
2141  if ( plInBuildTree() == 1 )
2142  {
2143  plGetName( BUILD_DIR, "bindings/tk", fn, &fs );
2144  if ( !plFindName( fs ) )
2145  return fs;
2146  else
2147  {
2148  plGetName( SOURCE_DIR, "scripts", fn, &fs );
2149  if ( !plFindName( fs ) )
2150  return fs;
2151  }
2152  }
2153 
2154 // PLPLOT_BIN_ENV = $(PLPLOT_BIN)
2155 
2156 #if defined ( PLPLOT_BIN_ENV )
2157  if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL )
2158  {
2159  plGetName( dn, "", fn, &fs );
2160  if ( !plFindName( fs ) )
2161  return fs;
2162  fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); // what IS set?
2163  }
2164 #endif // PLPLOT_BIN_ENV
2165 
2166 // Current directory
2167 
2168  plGetName( ".", "", fn, &fs );
2169  if ( !plFindName( fs ) )
2170  return fs;
2171 
2172 // PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
2173 
2174 #if defined ( PLPLOT_HOME_ENV )
2175  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2176  {
2177  plGetName( dn, "bin", fn, &fs );
2178  if ( !plFindName( fs ) )
2179  return fs;
2180  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2181  }
2182 #endif // PLPLOT_HOME_ENV
2183 
2184 // BIN_DIR
2185 
2186 #if defined ( BIN_DIR )
2187  plGetName( BIN_DIR, "", fn, &fs );
2188  if ( !plFindName( fs ) )
2189  return fs;
2190 #endif
2191 
2192 // Crapped out
2193 
2194  free_mem( fs );
2195  fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn );
2196 #if defined ( BIN_DIR )
2197  fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" ); // what WAS set?
2198 #endif // BIN_DIR
2199  return NULL;
2200 }
2201 
2202 //--------------------------------------------------------------------------
2203 // FILE *plLibOpen(fn)
2204 //
2216 //--------------------------------------------------------------------------
2217 
2218 FILE *
2219 plLibOpen( const char *fn )
2220 {
2221  FILE *ret = NULL;
2222 
2223  PDFstrm *pdfs = plLibOpenPdfstrm( fn );
2224  if ( pdfs == NULL )
2225  {
2226  return NULL;
2227  }
2228  if ( pdfs->file != NULL )
2229  {
2230  ret = pdfs->file;
2231  pdfs->file = NULL;
2232  }
2233  pdf_close( pdfs );
2234  return ret;
2235 }
2236 
2237 //--------------------------------------------------------------------------
2238 // FILE *plLibOpenPdfstrm(fn)
2239 //
2251 //--------------------------------------------------------------------------
2252 PDFstrm *
2253 plLibOpenPdfstrm( const char *fn )
2254 {
2255  PDFstrm *file;
2256  char *fs = NULL, *dn = NULL;
2257 
2258 //*** search build tree ***
2259 
2260  if ( plInBuildTree() == 1 )
2261  {
2262  plGetName( SOURCE_DIR, "data", fn, &fs );
2263 
2264  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2265  goto done;
2266  }
2267 
2268 //*** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ***
2269 
2270 #if defined ( PLPLOT_LIB_ENV )
2271  if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL )
2272  {
2273  plGetName( dn, "", fn, &fs );
2274 
2275  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2276  goto done;
2277  fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); // what IS set?
2278  }
2279 #endif // PLPLOT_LIB_ENV
2280 
2281 //*** search current directory ***
2282 
2283  if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL )
2284  {
2285  pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn );
2286  free_mem( fs );
2287  return ( file );
2288  }
2289 
2290 //*** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ***
2291 
2292 #if defined ( PLPLOT_HOME_ENV )
2293  if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
2294  {
2295  plGetName( dn, "lib", fn, &fs );
2296 
2297  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2298  goto done;
2299  fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
2300  }
2301 #endif // PLPLOT_HOME_ENV/lib
2302 
2303 //*** search installed location ***
2304 
2305 #if defined ( DATA_DIR )
2306  plGetName( DATA_DIR, "", fn, &fs );
2307 
2308  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2309  goto done;
2310 #endif // DATA_DIR
2311 
2312 //*** search hardwired location ***
2313 
2314 #ifdef PLLIBDEV
2315  plGetName( PLLIBDEV, "", fn, &fs );
2316 
2317  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2318  goto done;
2319 #endif // PLLIBDEV
2320 
2321 #ifdef macintosh
2322  file = plMacLibOpen( fn );
2323  if ( file != NULL )
2324  goto done;
2325 #endif // macintosh
2326 
2327  if ( plplotLibDir != NULL )
2328  {
2329  plGetName( plplotLibDir, "", fn, &fs );
2330  if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
2331  goto done;
2332  }
2333 
2334 //*** not found, give up ***
2335  pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn );
2336  free_mem( fs );
2337  return NULL;
2338 
2339 done:
2340  pldebug( "plLibOpenPdfstr", "Found file %s\n", fs );
2341  free_mem( fs );
2342  return ( file );
2343 }
2344 
2345 //--------------------------------------------------------------------------
2346 // int plFindName
2347 //
2365 //--------------------------------------------------------------------------
2366 
2367 #ifdef __unix
2368 int
2369 plFindName( char *p )
2370 {
2371  ssize_t n;
2372  char buf[PLPLOT_MAX_PATH], *cp;
2373  struct stat sbuf;
2374 
2375  pldebug( "plFindName", "Trying to find %s\n", p );
2376  while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 )
2377  {
2378  pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p );
2379  if ( buf[0] == '/' )
2380  {
2381  // Link is an absolute path
2382 
2383  strncpy( p, buf, (size_t) n );
2384  p[n] = '\0';
2385  pldebug( "plFindName", "Link is absolute: %s\n", p );
2386  }
2387  else
2388  {
2389  // Link is relative to its directory; make it absolute
2390 
2391  cp = 1 + strrchr( p, '/' );
2392  strncpy( cp, buf, (size_t) n );
2393  cp[n] = '\0';
2394  pldebug( "plFindName",
2395  "Link is relative: %s\n\tTotal path:%s\n", cp, p );
2396  }
2397  }
2398 
2399 // This macro not defined on the NEC SX-3
2400 
2401 #ifdef SX
2402 #define S_ISREG( mode ) ( mode & S_IFREG )
2403 #endif
2404 
2405 // SGI machines return ENXIO instead of EINVAL Dubois 11/92
2406 
2407  if ( errno == EINVAL || errno == ENXIO )
2408  {
2409  pldebug( "plFindName", "%s may be the one...\n", p );
2410  if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) )
2411  {
2412  pldebug( "plFindName", "%s is a regular file\n", p );
2413  return ( access( p, X_OK ) );
2414  }
2415  }
2416  pldebug( "plFindName", "%s found but is not executable\n", p );
2417  return ( errno ? errno : -1 );
2418 }
2419 
2420 #else
2421 int
2422 plFindName( char *p )
2423 {
2424  return 1;
2425 }
2426 #endif
2427 
2428 //--------------------------------------------------------------------------
2429 // void plGetName()
2430 //
2440 //--------------------------------------------------------------------------
2441 
2442 void
2443 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec )
2444 {
2445  size_t lfilespec;
2446 
2447 // Malloc space for filespec
2448 
2449  free_mem( *filespec );
2450  // Be slightly generous since 3 (two delimiters + NULL byte) should be
2451  // enough.
2452  lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10;
2453  if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL )
2454  {
2455  plexit( "plGetName: Insufficient memory" );
2456  }
2457 
2458  strcpy( *filespec, dir );
2459 
2460  if ( *subdir != '\0' )
2461  {
2462  strcat_delim( *filespec );
2463  strcat( *filespec, subdir );
2464  }
2465  if ( *filename != '\0' )
2466  {
2467  strcat_delim( *filespec );
2468  strcat( *filespec, filename );
2469  }
2470 #ifdef WIN32
2471  // According to http://msdn.microsoft.com/en-us/library/vstudio/tcxf1dw6.aspx
2472  // and also Wine tests, Microsoft does not support the c99 standard %zu
2473  // format. Instead, %lu is recommended for size_t.
2474  pldebug( "plGetName", "Maximum length of full pathname of file to be found is %lu\n", lfilespec - 1 );
2475 #else
2476  pldebug( "plGetName", "Maximum length of full pathname of file to be found is %zu\n", lfilespec - 1 );
2477 #endif
2478  pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec );
2479 }
2480 
2481 //--------------------------------------------------------------------------
2482 // void strcat_delim()
2483 //
2488 //--------------------------------------------------------------------------
2489 
2490 void
2491 strcat_delim( char *dirspec )
2492 {
2493  size_t ldirspec = strlen( dirspec );
2494 #if defined ( MSDOS ) || defined ( WIN32 )
2495  if ( dirspec[ldirspec - 1] != '\\' )
2496  strcat( dirspec, "\\" );
2497 #elif defined ( macintosh )
2498  if ( dirspec[ldirspec - 1] != ':' )
2499  strcat( dirspec, ":" );
2500 #else // unix is the default
2501  if ( dirspec[ldirspec - 1] != '/' )
2502  strcat( dirspec, "/" );
2503 #endif
2504 }
2505 
2506 //--------------------------------------------------------------------------
2507 // plcol_interp()
2508 //
2517 //--------------------------------------------------------------------------
2518 
2519 void
2520 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
2521 {
2522  PLFLT x, delta;
2523  int il, ir;
2524 
2525  x = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 );
2526  il = (int) x;
2527  ir = il + 1;
2528  delta = x - il;
2529 
2530  if ( ir > pls->ncol1 || il < 0 )
2531  fprintf( stderr, "Invalid color\n" );
2532 
2533  else if ( ir == pls->ncol1 || ( delta == 0. ) )
2534  {
2535  newcolor->r = pls->cmap1[il].r;
2536  newcolor->g = pls->cmap1[il].g;
2537  newcolor->b = pls->cmap1[il].b;
2538  newcolor->a = pls->cmap1[il].a;
2539  }
2540  else
2541  {
2542  newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r );
2543  newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g );
2544  newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b );
2545  newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a;
2546  }
2547 }
2548 
2549 //--------------------------------------------------------------------------
2550 // plOpenFile()
2551 //
2557 //--------------------------------------------------------------------------
2558 
2559 #define MAX_NUM_TRIES 10
2560 void
2562 {
2563  int i = 0, count = 0;
2564  size_t len;
2565  char line[BUFFER_SIZE];
2566 
2567  while ( pls->OutFile == NULL )
2568  {
2569 // Setting pls->FileName = NULL forces creation of a new family member
2570 // You should also free the memory associated with it if you do this
2571 
2572  if ( pls->family && pls->BaseName != NULL )
2573  plP_getmember( pls );
2574 
2575 // Prompt if filename still not known
2576 
2577  if ( pls->FileName == NULL )
2578  {
2579  do
2580  {
2581  fprintf( stdout, "Enter graphics output file name: " );
2582  plio_fgets( line, sizeof ( line ), stdin );
2583  len = strlen( line );
2584  if ( len )
2585  len--;
2586  line[len] = '\0'; // strip new-line
2587  count++; // count zero entries
2588  } while ( !len && count < MAX_NUM_TRIES );
2589  plP_sfnam( pls, line );
2590  }
2591 
2592 // If name is "-", send to stdout
2593 
2594  if ( !strcmp( pls->FileName, "-" ) )
2595  {
2596  pls->OutFile = stdout;
2597  pls->output_type = 1;
2598  break;
2599  }
2600 
2601 // Need this here again, for prompted family initialization
2602 
2603  if ( pls->family && pls->BaseName != NULL )
2604  plP_getmember( pls );
2605 
2606  if ( i++ > 10 )
2607  plexit( "Too many tries." );
2608 
2609  if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
2610  fprintf( stderr, "Can't open %s.\n", pls->FileName );
2611  else
2612  pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
2613  }
2614 }
2615 
2616 //--------------------------------------------------------------------------
2617 // plCloseFile()
2618 //
2622 //--------------------------------------------------------------------------
2623 
2624 void
2626 {
2627  if ( pls->OutFile != NULL )
2628  {
2629  // Don't close if the output file was stdout
2630  if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 )
2631  return;
2632 
2633  fclose( pls->OutFile );
2634  pls->OutFile = NULL;
2635  }
2636 }
2637 
2638 //--------------------------------------------------------------------------
2639 // plP_getmember()
2640 //
2644 //--------------------------------------------------------------------------
2645 
2646 void
2648 {
2649  char tmp[BUFFER_SIZE];
2650  char prefix[BUFFER_SIZE];
2651  char * suffix;
2652  char num[BUFFER_SIZE];
2653  size_t maxlen;
2654 
2655  maxlen = strlen( pls->BaseName ) + 10;
2656  if ( pls->FileName == NULL )
2657  {
2658  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2659  {
2660  plexit( "plP_getmember: Insufficient memory" );
2661  }
2662  }
2663 
2664  suffix = strstr( pls->BaseName, "%n" );
2665 
2666  snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen );
2667  snprintf( num, BUFFER_SIZE, tmp, pls->member );
2668 
2669  if ( suffix == NULL )
2670  snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num );
2671  else
2672  {
2673  strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 );
2674  prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0';
2675  snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 );
2676  }
2677 }
2678 
2679 //--------------------------------------------------------------------------
2680 // plP_sfnam()
2681 //
2687 //--------------------------------------------------------------------------
2688 
2689 void
2690 plP_sfnam( PLStream *pls, const char *fnam )
2691 {
2692  char prefix[BUFFER_SIZE];
2693  char * suffix;
2694  size_t maxlen;
2695  pls->OutFile = NULL;
2696 
2697  if ( pls->FileName != NULL )
2698  free( (void *) pls->FileName );
2699 
2700  maxlen = 10 + strlen( fnam );
2701  if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
2702  {
2703  plexit( "plP_sfnam: Insufficient memory" );
2704  }
2705 
2706  suffix = strstr( fnam, "%n" );
2707 
2708  if ( suffix == NULL )
2709  {
2710  strncpy( pls->FileName, fnam, maxlen - 1 );
2711  pls->FileName[maxlen - 1] = '\0';
2712  }
2713  else
2714  {
2715  strncpy( prefix, fnam, BUFFER_SIZE - 1 );
2716  prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0';
2717  snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 );
2718  }
2719 
2720  if ( pls->BaseName != NULL )
2721  free( (void *) pls->BaseName );
2722 
2723  if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL )
2724  {
2725  plexit( "plP_sfnam: Insufficient memory" );
2726  }
2727 
2728  strncpy( pls->BaseName, fnam, maxlen - 1 );
2729  pls->BaseName[maxlen - 1] = '\0';
2730 }
2731 
2732 //--------------------------------------------------------------------------
2733 // plFamInit()
2734 //
2738 //--------------------------------------------------------------------------
2739 
2740 void
2742 {
2743  if ( pls->family )
2744  {
2745  pls->bytecnt = 0;
2746  if ( !pls->member )
2747  pls->member = 1;
2748  if ( !pls->finc )
2749  pls->finc = 1;
2750  if ( !pls->fflen )
2751  pls->fflen = 1;
2752  if ( !pls->bytemax )
2753  pls->bytemax = PL_FILESIZE_KB * 1000;
2754  }
2755 }
2756 
2757 //--------------------------------------------------------------------------
2758 // plGetFam()
2759 //
2767 //--------------------------------------------------------------------------
2768 
2769 void
2771 {
2772  PLFLT xpmm_loc, ypmm_loc;
2773  if ( pls->family )
2774  {
2775  if ( pls->bytecnt > pls->bytemax || pls->famadv )
2776  {
2777  PLINT local_page_status = pls->page_status;
2778  plP_tidy();
2779  pls->member += pls->finc;
2780  pls->famadv = 0;
2781  plP_init();
2782  // Restore page status (normally AT_BOP) that was changed
2783  // to AT_EOP by plP_init.
2784  pls->page_status = local_page_status;
2785 
2786  // Apply compensating factor to original xpmm and ypmm so that
2787  // character aspect ratio is preserved when overall aspect ratio
2788  // is changed.
2789  plP_gpixmm( &xpmm_loc, &ypmm_loc );
2790  plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
2791  return;
2792  }
2793  }
2794 }
2795 
2796 //--------------------------------------------------------------------------
2797 // plRotPhy()
2798 //
2811 //--------------------------------------------------------------------------
2812 
2813 void
2815  PLINT *px, PLINT *py )
2816 {
2817  int x, y;
2818 
2819  x = *px;
2820  y = *py;
2821 
2822  switch ( orient % 4 )
2823  {
2824  case 1:
2825  *px = xmin + ( y - ymin );
2826  *py = ymin + ( xmax - x );
2827  break;
2828 
2829  case 2:
2830  *px = xmin + ( xmax - x );
2831  *py = ymin + ( ymax - y );
2832  break;
2833 
2834  case 3:
2835  *px = xmin + ( ymax - y );
2836  *py = ymin + ( x - xmin );
2837  break;
2838 
2839  default:
2840  break; // do nothing
2841  }
2842 }
2843 
2844 //--------------------------------------------------------------------------
2845 // plAllocDev()
2846 //
2853 //--------------------------------------------------------------------------
2854 
2855 PLDev *
2857 {
2858  if ( pls->dev != NULL )
2859  free( (void *) pls->dev );
2860 
2861  pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) );
2862  if ( pls->dev == NULL )
2863  plexit( "plAllocDev: cannot allocate memory\n" );
2864 
2865  return (PLDev *) pls->dev;
2866 }
2867 
2868 //--------------------------------------------------------------------------
2869 // plGinInit()
2870 //
2874 //--------------------------------------------------------------------------
2875 
2876 void
2878 {
2879  gin->type = 0;
2880  gin->state = 0;
2881  gin->keysym = 0;
2882  gin->button = 0;
2883  gin->string[0] = '\0';
2884  gin->pX = gin->pY = -1;
2885  gin->dX = gin->dY = 0.;
2886  gin->wX = gin->wY = 0.;
2887 }
2888 
2889 //--------------------------------------------------------------------------
2890 // plGetInt()
2891 //
2897 //--------------------------------------------------------------------------
2898 
2899 PLINT
2900 plGetInt( const char *s )
2901 {
2902  int m;
2903  int i = 0;
2904  char line[BUFFER_SIZE];
2905 
2906  while ( i++ < 10 )
2907  {
2908  fputs( s, stdout );
2909  plio_fgets( line, sizeof ( line ), stdin );
2910 
2911 #ifdef MSDOS
2912  m = atoi( line );
2913  return ( m );
2914 #else
2915  if ( sscanf( line, "%d", &m ) == 1 )
2916  return ( m );
2917  fprintf( stdout, "No value or value out of range; please try again\n" );
2918 #endif
2919  }
2920  plexit( "Too many tries." );
2921  return ( 0 );
2922 }
2923 
2924 //--------------------------------------------------------------------------
2925 // plGetFlt()
2926 //
2932 //--------------------------------------------------------------------------
2933 
2934 PLFLT
2935 plGetFlt( const char *s )
2936 {
2937  PLFLT m;
2938  double m1;
2939  int i = 0;
2940  char line[BUFFER_SIZE];
2941 
2942  while ( i++ < 10 )
2943  {
2944  fputs( s, stdout );
2945  plio_fgets( line, sizeof ( line ), stdin );
2946 
2947 #ifdef MSDOS
2948  m = atof( line );
2949  return ( m );
2950 #else
2951  if ( sscanf( line, "%lf", &m1 ) == 1 )
2952  {
2953  m = (PLFLT) m1;
2954  return ( m );
2955  }
2956  fprintf( stdout, "No value or value out of range; please try again\n" );
2957 #endif
2958  }
2959  plexit( "Too many tries." );
2960  return ( 0. );
2961 }
2962 
2963 //--------------------------------------------------------------------------
2964 // plstrdup()
2965 //
2972 //--------------------------------------------------------------------------
2973 
2974 char PLDLLIMPEXP *
2975 plstrdup( const char *src )
2976 {
2977  char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) );
2978  if ( dest != NULL )
2979  strcpy( dest, src );
2980  else
2981  plabort( "Out of memory" );
2982 
2983  return dest;
2984 }
2985 
2986 #ifndef PL_HAVE_SNPRINTF
2987 //--------------------------------------------------------------------------
2988 // plsnprintf()
2989 //
3000 //--------------------------------------------------------------------------
3001 
3002 int
3003 plsnprintf( char *buffer, int n, const char *format, ... )
3004 {
3005  int ret;
3006 
3007  va_list args;
3008  va_start( args, format );
3009  ret = vsprintf( buffer, format, args );
3010  va_end( args );
3011 
3012  // Check if overrun occured
3013  if ( ret > n - 1 )
3014  plabort( "plsnprintf: buffer overrun" );
3015 
3016  return ret;
3017 }
3018 
3019 //--------------------------------------------------------------------------
3020 // plsnscanf()
3021 //
3032 //--------------------------------------------------------------------------
3033 
3034 int
3035 plsnscanf( const char *buffer, int n, const char *format, ... )
3036 {
3037  int ret;
3038 
3039  va_list args;
3040  va_start( args, format );
3041  ret = vsscanf( buffer, format, args );
3042  va_end( args );
3043 
3044  return ret;
3045 }
3046 
3047 #endif // PL_HAVE_SNPRINTF
3048 
3049 //--------------------------------------------------------------------------
3050 // plseed()
3051 //
3055 //--------------------------------------------------------------------------
3056 
3057 void
3058 c_plseed( unsigned int seed )
3059 {
3060  init_genrand( seed );
3061 }
3062 
3063 //--------------------------------------------------------------------------
3064 // plrandd()
3065 //
3068 //--------------------------------------------------------------------------
3069 
3070 PLFLT
3071 c_plrandd( void )
3072 {
3073  return (PLFLT) ( genrand_real1() );
3074 }
3075 
3076 //--------------------------------------------------------------------------
3077 // plsave_set_locale()
3078 //
3088 //--------------------------------------------------------------------------
3089 
3090 char *
3092 {
3093  char * setlocale_ptr;
3094  char * saved_lc_numeric_locale;
3095 
3096  if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) )
3097  {
3098  plexit( "plsave_set_locale: out of memory" );
3099  }
3100 
3101  //save original LC_NUMERIC locale for restore below.
3102  if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) )
3103  {
3104  plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" );
3105  }
3106  strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 );
3107  saved_lc_numeric_locale[99] = '\0';
3108 
3109  // Do not use pldebug since get overflowed stack (infinite recursion)
3110  // if device is interactive (i.e., pls->termin is set).
3111  // comment out fprintf (unless there is some emergency debugging to do)
3112  // because output is too voluminous.
3113  //
3114  // fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3115  //
3116 
3117  if ( !( setlocale( LC_NUMERIC, "C" ) ) )
3118  {
3119  plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" );
3120  }
3121  return saved_lc_numeric_locale;
3122 }
3123 
3124 //--------------------------------------------------------------------------
3125 // plrestore_locale()
3126 //
3132 //--------------------------------------------------------------------------
3133 
3134 void
3135 plrestore_locale( char *saved_lc_numeric_locale )
3136 {
3137  // Do not use pldebug since get overflowed stack (infinite recursion)
3138  // if device is interactive (i.e., pls->termin is set).
3139  // comment out fprintf (unless there is some emergency debugging to do)
3140  // because output is too voluminous.
3141  //
3142  // fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
3143  //
3144 
3145  if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
3146  {
3147  char msgbuf[1024];
3148  snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
3149  plexit( msgbuf );
3150  }
3151  free( saved_lc_numeric_locale );
3152 }
3153