PLplot  5.10.0
plctrl.c
Go to the documentation of this file.
00001 //      Misc. control routines, like begin, end, exit, change graphics/text
00002 //      mode, change color.  Includes some spillage from plcore.c.  If you
00003 //      don't know where it should go, put it here.
00004 //
00005 // Copyright (C) 2004  Joao Cardoso
00006 // Copyright (C) 2004  Rafael Laboissiere
00007 // Copyright (C) 2008  Hazen Babcock
00008 // Copyright (C) 2009-2014 Alan W. Irwin
00009 // Copyright (C) 2011  Hezekiah M. Carty
00010 //
00011 // This file is part of PLplot.
00012 //
00013 // PLplot is free software; you can redistribute it and/or modify
00014 // it under the terms of the GNU Library General Public License as published
00015 // by the Free Software Foundation; either version 2 of the License, or
00016 // (at your option) any later version.
00017 //
00018 // PLplot is distributed in the hope that it will be useful,
00019 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 // GNU Library General Public License for more details.
00022 //
00023 // You should have received a copy of the GNU Library General Public License
00024 // along with PLplot; if not, write to the Free Software
00025 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00026 //
00027 //
00028 
00034 
00035 #define DEBUG
00036 
00037 #define NEED_PLDEBUG
00038 #include "plplotP.h"
00039 #ifdef macintosh
00040 #include "mac.h"
00041 // for plMacLibOpen prototype; used in plLibOpen
00042 #endif
00043 
00044 #ifdef DJGPP                    // dos386/djgpp
00045 #ifdef __unix
00046 #undef __unix
00047 #endif
00048 #endif
00049 
00050 #ifdef __unix
00051 #include <sys/types.h>
00052 #include <sys/stat.h>
00053 #ifdef PL_HAVE_UNISTD_H
00054 #include <unistd.h>
00055 #endif
00056 #include <errno.h>
00057 #endif
00058 
00059 // Random number generator (Mersenne Twister)
00060 #include "mt19937ar.h"
00061 
00062 #define BUFFER_SIZE    256
00063 #define COLLEN         30
00064 #define PALLEN         160
00065 #define MSGLEN         1024
00066 
00067 // small epsilon for fuzzy range checks that is still large enough to
00068 // work even in the single precision floating point case.
00069 #define FUZZ_EPSILON    1.e-4
00070 
00071 // Static functions
00072 
00073 // Used by any external init code to suggest a path
00074 char PLDLLIMPEXP * plplotLibDir = 0;
00075 
00076 static void
00077 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name );
00078 
00079 static void
00080 strcat_delim( char *dirspec );
00081 
00082 static int
00083 ( *exit_handler )( const char *errormsg );
00084 
00085 static void
00086 ( *abort_handler )( const char *errormsg );
00087 
00088 static void
00089 plcmap0_def( int imin, int imax );
00090 
00091 static void
00092 plcmap1_def( void );
00093 
00094 static PLFLT
00095 value( double n1, double n2, double hue );
00096 
00097 static char *
00098 read_line( char *buffer, int length, FILE *fp );
00099 
00100 static void
00101 cmap0_palette_read( const char *filename,
00102                     int *number_colors, unsigned int **r, unsigned int **g,
00103                     unsigned int **b, double **a );
00104 
00105 // An additional hardwired location for lib files.
00106 // I have no plans to change these again, ever.
00107 
00108 #if defined ( DJGPP )
00109 #ifndef PLLIBDEV
00110 #define PLLIBDEV    "c:/plplot/lib"
00111 #endif
00112 
00113 #elif defined ( MSDOS )
00114 #ifndef PLLIBDEV
00115 #define PLLIBDEV    "c:\\plplot\\lib"
00116 #endif
00117 
00118 #else
00119 
00120 // Anything else is assumed to be Unix
00121 
00122 #ifndef PLLIBDEV
00123 #define PLLIBDEV    "/usr/local/plplot/lib"
00124 #endif
00125 
00126 #endif
00127 
00128 //--------------------------------------------------------------------------
00129 //  Routines that deal with colors & color maps.
00130 //--------------------------------------------------------------------------
00131 
00132 //--------------------------------------------------------------------------
00133 // plcol0()
00134 //
00139 
00140 void
00141 c_plcol0( PLINT icol0 )
00142 {
00143     if ( plsc->level < 1 )
00144     {
00145         plabort( "plcol0: Please call plinit first" );
00146         return;
00147     }
00148     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00149     {
00150         char buffer[BUFFER_SIZE];
00151         snprintf( buffer, BUFFER_SIZE, "plcol0: Invalid color map entry: %d", (int) icol0 );
00152         plabort( buffer );
00153         return;
00154     }
00155 
00156     plsc->icol0      = icol0;
00157     plsc->curcolor.r = plsc->cmap0[icol0].r;
00158     plsc->curcolor.g = plsc->cmap0[icol0].g;
00159     plsc->curcolor.b = plsc->cmap0[icol0].b;
00160     plsc->curcolor.a = plsc->cmap0[icol0].a;
00161 
00162     plsc->curcmap = 0;
00163     plP_state( PLSTATE_COLOR0 );
00164 }
00165 
00166 //--------------------------------------------------------------------------
00167 // plcol1()
00168 //
00173 
00174 void
00175 c_plcol1( PLFLT col1 )
00176 {
00177     PLINT icol1;
00178 
00179     if ( plsc->level < 1 )
00180     {
00181         plabort( "plcol1: Please call plinit first" );
00182         return;
00183     }
00184     if ( col1 < 0 || col1 > 1 || isnan( col1 ) )
00185     {
00186         char buffer[BUFFER_SIZE];
00187         snprintf( buffer, BUFFER_SIZE, "plcol1: Invalid color map position: %f", (PLFLT) col1 );
00188         plabort( buffer );
00189         return;
00190     }
00191 
00192     icol1 = (PLINT) ( col1 * plsc->ncol1 );
00193     icol1 = MIN( icol1, plsc->ncol1 - 1 );
00194 
00195     plsc->icol1      = icol1;
00196     plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
00197     plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
00198     plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
00199     plsc->curcolor.a = plsc->cmap1[plsc->icol1].a;
00200 
00201     plsc->curcmap = 1;
00202     plP_state( PLSTATE_COLOR1 );
00203 }
00204 
00205 //--------------------------------------------------------------------------
00206 // plscolbg()
00207 //
00213 
00214 void
00215 c_plscolbg( PLINT r, PLINT g, PLINT b )
00216 {
00217     plscol0( 0, r, g, b );
00218 }
00219 
00220 //--------------------------------------------------------------------------
00221 // plscolbga()
00222 //
00230 
00231 //--------------------------------------------------------------------------
00232 
00233 void
00234 c_plscolbga( PLINT r, PLINT g, PLINT b, PLFLT alpha )
00235 {
00236     plscol0a( 0, r, g, b, alpha );
00237 }
00238 
00239 //--------------------------------------------------------------------------
00240 // plgcolbg()
00241 //
00247 
00248 void
00249 c_plgcolbg( PLINT *r, PLINT *g, PLINT *b )
00250 {
00251     plgcol0( 0, r, g, b );
00252 }
00253 
00254 //--------------------------------------------------------------------------
00255 // plgcolbga()
00256 //
00263 
00264 void
00265 c_plgcolbga( PLINT *r, PLINT *g, PLINT *b, PLFLT *alpha )
00266 {
00267     plgcol0a( 0, r, g, b, alpha );
00268 }
00269 
00270 //--------------------------------------------------------------------------
00271 // plscol0()
00272 //
00280 
00281 void
00282 c_plscol0( PLINT icol0, PLINT r, PLINT g, PLINT b )
00283 {
00284     if ( plsc->cmap0 == NULL )
00285         plscmap0n( 0 );
00286     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00287     {
00288         char buffer[BUFFER_SIZE];
00289         snprintf( buffer, BUFFER_SIZE, "plscol0: Illegal color table value: %d", (int) icol0 );
00290         plabort( buffer );
00291         return;
00292     }
00293     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) )
00294     {
00295         char buffer[BUFFER_SIZE];
00296         snprintf( buffer, BUFFER_SIZE, "plscol0: Invalid RGB color: %d, %d, %d",
00297             (int) r, (int) g, (int) b );
00298         plabort( buffer );
00299         return;
00300     }
00301 
00302     plscol0a( icol0, r, g, b, 1.0 );
00303 }
00304 
00305 //--------------------------------------------------------------------------
00306 // plscol0a()
00307 //
00316 
00317 void
00318 c_plscol0a( PLINT icol0, PLINT r, PLINT g, PLINT b, PLFLT alpha )
00319 {
00320     if ( plsc->cmap0 == NULL )
00321         plscmap0n( 0 );
00322     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00323     {
00324         char buffer[BUFFER_SIZE];
00325         snprintf( buffer, BUFFER_SIZE, "plscol0a: Illegal color table value: %d", (int) icol0 );
00326         plabort( buffer );
00327         return;
00328     }
00329     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) || ( alpha < 0. || alpha > 1.0 ) )
00330     {
00331         char buffer[BUFFER_SIZE];
00332         snprintf( buffer, BUFFER_SIZE, "plscol0a: Invalid RGB color: %d, %d, %d, %f",
00333             (int) r, (int) g, (int) b, (double) alpha );
00334         plabort( buffer );
00335         return;
00336     }
00337 
00338     plsc->cmap0[icol0].r = (unsigned char) r;
00339     plsc->cmap0[icol0].g = (unsigned char) g;
00340     plsc->cmap0[icol0].b = (unsigned char) b;
00341     plsc->cmap0[icol0].a = alpha;
00342 
00343     if ( plsc->level > 0 )
00344         plP_state( PLSTATE_CMAP0 );
00345 }
00346 
00347 //--------------------------------------------------------------------------
00348 // plgcol0()
00349 //
00357 
00358 void
00359 c_plgcol0( PLINT icol0, PLINT *r, PLINT *g, PLINT *b )
00360 {
00361     if ( plsc->cmap0 == NULL )
00362         plscmap0n( 0 );
00363 
00364     *r = -1;
00365     *g = -1;
00366     *b = -1;
00367 
00368     if ( icol0 < 0 || icol0 > plsc->ncol0 )
00369     {
00370         char buffer[BUFFER_SIZE];
00371         snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
00372         plabort( buffer );
00373         return;
00374     }
00375 
00376     *r = plsc->cmap0[icol0].r;
00377     *g = plsc->cmap0[icol0].g;
00378     *b = plsc->cmap0[icol0].b;
00379 
00380     return;
00381 }
00382 
00383 //--------------------------------------------------------------------------
00384 // plgcol0a()
00385 //
00394 
00395 void
00396 c_plgcol0a( PLINT icol0, PLINT *r, PLINT *g, PLINT *b, PLFLT *alpha )
00397 {
00398     if ( plsc->cmap0 == NULL )
00399         plscmap0n( 0 );
00400 
00401     *r     = -1;
00402     *g     = -1;
00403     *b     = -1;
00404     *alpha = -1.0;
00405 
00406     if ( icol0 < 0 || icol0 > plsc->ncol0 )
00407     {
00408         char buffer[BUFFER_SIZE];
00409         snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
00410         plabort( buffer );
00411         return;
00412     }
00413 
00414     *r     = plsc->cmap0[icol0].r;
00415     *g     = plsc->cmap0[icol0].g;
00416     *b     = plsc->cmap0[icol0].b;
00417     *alpha = plsc->cmap0[icol0].a;
00418 
00419     return;
00420 }
00421 
00422 //--------------------------------------------------------------------------
00423 // plscmap0()
00424 //
00432 
00433 void
00434 c_plscmap0( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol0 )
00435 {
00436     int i;
00437 
00438     plscmap0n( ncol0 );
00439 
00440     for ( i = 0; i < plsc->ncol0; i++ )
00441     {
00442         if ( ( r[i] < 0 || r[i] > 255 ) ||
00443              ( g[i] < 0 || g[i] > 255 ) ||
00444              ( b[i] < 0 || b[i] > 255 ) )
00445         {
00446             char buffer[BUFFER_SIZE];
00447             snprintf( buffer, BUFFER_SIZE, "plscmap0: Invalid RGB color: %d, %d, %d",
00448                 (int) r[i], (int) g[i], (int) b[i] );
00449             plabort( buffer );
00450             return;
00451         }
00452 
00453         plsc->cmap0[i].r = (unsigned char) r[i];
00454         plsc->cmap0[i].g = (unsigned char) g[i];
00455         plsc->cmap0[i].b = (unsigned char) b[i];
00456         plsc->cmap0[i].a = 1.0;
00457     }
00458 
00459     if ( plsc->level > 0 )
00460         plP_state( PLSTATE_CMAP0 );
00461 }
00462 
00463 //--------------------------------------------------------------------------
00464 // plscmap0a()
00465 //
00474 
00475 void
00476 c_plscmap0a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *alpha, PLINT ncol0 )
00477 {
00478     int i;
00479 
00480     plscmap0n( ncol0 );
00481 
00482     for ( i = 0; i < plsc->ncol0; i++ )
00483     {
00484         if ( ( r[i] < 0 || r[i] > 255 ) ||
00485              ( g[i] < 0 || g[i] > 255 ) ||
00486              ( b[i] < 0 || b[i] > 255 ) ||
00487              ( alpha[i] < 0.0 || alpha[i] > 1.0 ) )
00488         {
00489             char buffer[BUFFER_SIZE];
00490             snprintf( buffer, BUFFER_SIZE, "plscmap0a: Invalid RGB color: %d, %d, %d, %f",
00491                 (int) r[i], (int) g[i], (int) b[i], (double) alpha[i] );
00492             plabort( buffer );
00493             return;
00494         }
00495 
00496         plsc->cmap0[i].r = (unsigned char) r[i];
00497         plsc->cmap0[i].g = (unsigned char) g[i];
00498         plsc->cmap0[i].b = (unsigned char) b[i];
00499         plsc->cmap0[i].a = alpha[i];
00500     }
00501 
00502     if ( plsc->level > 0 )
00503         plP_state( PLSTATE_CMAP0 );
00504 }
00505 
00506 //--------------------------------------------------------------------------
00507 // plscmap1()
00508 //
00516 
00517 void
00518 c_plscmap1( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol1 )
00519 {
00520     int i;
00521 
00522     plscmap1n( ncol1 );
00523 
00524     for ( i = 0; i < plsc->ncol1; i++ )
00525     {
00526         if ( ( r[i] < 0 || r[i] > 255 ) ||
00527              ( g[i] < 0 || g[i] > 255 ) ||
00528              ( b[i] < 0 || b[i] > 255 ) )
00529         {
00530             char buffer[BUFFER_SIZE];
00531             snprintf( buffer, BUFFER_SIZE, "plscmap1: Invalid RGB color: %d, %d, %d",
00532                 (int) r[i], (int) g[i], (int) b[i] );
00533             plabort( buffer );
00534             return;
00535         }
00536         plsc->cmap1[i].r = (unsigned char) r[i];
00537         plsc->cmap1[i].g = (unsigned char) g[i];
00538         plsc->cmap1[i].b = (unsigned char) b[i];
00539         plsc->cmap1[i].a = 1.0;
00540     }
00541 
00542     if ( plsc->level > 0 )
00543         plP_state( PLSTATE_CMAP1 );
00544 }
00545 
00546 //--------------------------------------------------------------------------
00547 // plscmap1a()
00548 //
00557 
00558 void
00559 c_plscmap1a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *alpha, PLINT ncol1 )
00560 {
00561     int i;
00562 
00563     plscmap1n( ncol1 );
00564 
00565     for ( i = 0; i < plsc->ncol1; i++ )
00566     {
00567         if ( ( r[i] < 0 || r[i] > 255 ) ||
00568              ( g[i] < 0 || g[i] > 255 ) ||
00569              ( b[i] < 0 || b[i] > 255 ) ||
00570              ( alpha[i] < 0.0 || alpha[i] > 1.0 ) )
00571         {
00572             char buffer[BUFFER_SIZE];
00573             snprintf( buffer, BUFFER_SIZE, "plscmap1a: Invalid RGB color: %d, %d, %d, %f",
00574                 (int) r[i], (int) g[i], (int) b[i], (double) alpha[i] );
00575             plabort( buffer );
00576             return;
00577         }
00578         plsc->cmap1[i].r = (unsigned char) r[i];
00579         plsc->cmap1[i].g = (unsigned char) g[i];
00580         plsc->cmap1[i].b = (unsigned char) b[i];
00581         plsc->cmap1[i].a = alpha[i];
00582     }
00583 
00584     if ( plsc->level > 0 )
00585         plP_state( PLSTATE_CMAP1 );
00586 }
00587 
00588 //--------------------------------------------------------------------------
00589 // plscmap1l()
00590 //
00639 
00640 void
00641 c_plscmap1l( PLINT itype, PLINT npts, const PLFLT *intensity,
00642              const PLFLT *coord1, const PLFLT *coord2, const PLFLT *coord3, const PLINT *alt_hue_path )
00643 {
00644     int   n;
00645     PLFLT h, l, s, r, g, b;
00646 
00647     if ( npts < 2 )
00648     {
00649         plabort( "plscmap1l: Must specify at least two control points" );
00650         return;
00651     }
00652 
00653     if ( ( intensity[0] != 0 ) || ( intensity[npts - 1] != 1 ) )
00654     {
00655         plabort( "plscmap1l: First, last control points must lie on boundary" );
00656         return;
00657     }
00658 
00659     if ( npts > PL_MAX_CMAP1CP )
00660     {
00661         plabort( "plscmap1l: exceeded maximum number of control points" );
00662         return;
00663     }
00664 
00665 // Allocate if not done yet
00666 
00667     if ( plsc->cmap1 == NULL )
00668         plscmap1n( 0 );
00669 
00670 // Save control points
00671 
00672     plsc->ncp1 = npts;
00673 
00674     for ( n = 0; n < npts; n++ )
00675     {
00676         if ( itype == 0 )
00677         {
00678             h = coord1[n];
00679             l = coord2[n];
00680             s = coord3[n];
00681         }
00682         else
00683         {
00684             r = coord1[n];
00685             g = coord2[n];
00686             b = coord3[n];
00687             c_plrgbhls( r, g, b, &h, &l, &s );
00688         }
00689 
00690         plsc->cmap1cp[n].h = h;
00691         plsc->cmap1cp[n].l = l;
00692         plsc->cmap1cp[n].s = s;
00693         plsc->cmap1cp[n].p = intensity[n];
00694         plsc->cmap1cp[n].a = 1.0;
00695 
00696         if ( alt_hue_path == NULL )
00697             plsc->cmap1cp[n].alt_hue_path = 0;
00698         else
00699         if ( n != npts - 1 )
00700             plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
00701         else
00702             // Note final element is unused, so we set to zero for completeness.
00703             plsc->cmap1cp[n].alt_hue_path = 0;
00704     }
00705 
00706 // Calculate and set color map
00707 
00708     plcmap1_calc();
00709 }
00710 
00711 //--------------------------------------------------------------------------
00712 // plscmap1la()
00713 //
00725 
00726 void
00727 c_plscmap1la( PLINT itype, PLINT npts, const PLFLT *intensity,
00728               const PLFLT *coord1, const PLFLT *coord2, const PLFLT *coord3, const PLFLT *alpha, const PLINT *alt_hue_path )
00729 {
00730     int   n;
00731     PLFLT h, l, s, r, g, b;
00732 
00733     if ( npts < 2 )
00734     {
00735         plabort( "plscmap1la: Must specify at least two control points" );
00736         return;
00737     }
00738 
00739     if ( ( intensity[0] != 0 ) || ( intensity[npts - 1] != 1 ) )
00740     {
00741         plabort( "plscmap1la: First, last control points must lie on boundary" );
00742         return;
00743     }
00744 
00745     if ( npts > PL_MAX_CMAP1CP )
00746     {
00747         plabort( "plscmap1la: exceeded maximum number of control points" );
00748         return;
00749     }
00750 
00751 // Allocate if not done yet
00752 
00753     if ( plsc->cmap1 == NULL )
00754         plscmap1n( 0 );
00755 
00756 // Save control points
00757 
00758     plsc->ncp1 = npts;
00759 
00760     for ( n = 0; n < npts; n++ )
00761     {
00762         if ( itype == 0 )
00763         {
00764             h = coord1[n];
00765             l = coord2[n];
00766             s = coord3[n];
00767         }
00768         else
00769         {
00770             r = coord1[n];
00771             g = coord2[n];
00772             b = coord3[n];
00773             c_plrgbhls( r, g, b, &h, &l, &s );
00774         }
00775 
00776         plsc->cmap1cp[n].h = h;
00777         plsc->cmap1cp[n].l = l;
00778         plsc->cmap1cp[n].s = s;
00779         plsc->cmap1cp[n].p = intensity[n];
00780         plsc->cmap1cp[n].a = alpha[n];
00781 
00782         if ( alt_hue_path == NULL )
00783             plsc->cmap1cp[n].alt_hue_path = 0;
00784         else
00785         if ( n != npts - 1 )
00786             plsc->cmap1cp[n].alt_hue_path = alt_hue_path[n];
00787         else
00788             // Note final element is unused, so we set to zero for completeness.
00789             plsc->cmap1cp[n].alt_hue_path = 0;
00790     }
00791 
00792 // Calculate and set color map
00793 
00794     plcmap1_calc();
00795 }
00796 
00797 //--------------------------------------------------------------------------
00798 // plcmap1_calc()
00799 //
00802 
00803 void
00804 plcmap1_calc( void )
00805 {
00806     int   i, n;
00807     PLFLT delta, dp, dh, dl, ds, da;
00808     PLFLT h, l, s, p, r, g, b, a;
00809 
00810 // Loop over all control point pairs
00811 
00812     for ( n = 0; n < plsc->ncp1 - 1; n++ )
00813     {
00814         if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n + 1].p )
00815             continue;
00816 
00817         // Differences in p, h, l, s between ctrl pts
00818 
00819         dp = plsc->cmap1cp[n + 1].p - plsc->cmap1cp[n].p;
00820         dh = plsc->cmap1cp[n + 1].h - plsc->cmap1cp[n].h;
00821         dl = plsc->cmap1cp[n + 1].l - plsc->cmap1cp[n].l;
00822         ds = plsc->cmap1cp[n + 1].s - plsc->cmap1cp[n].s;
00823         da = plsc->cmap1cp[n + 1].a - plsc->cmap1cp[n].a;
00824 
00825         // Adjust dh if we are to go around "the back side"
00826 
00827         if ( plsc->cmap1cp[n].alt_hue_path )
00828             dh = ( dh > 0 ) ? dh - 360 : dh + 360;
00829 
00830         // Loop over all color cells.  Only interested in cells located (in
00831         // cmap1 space)  between n_th and n+1_th control points
00832 
00833         for ( i = 0; i < plsc->ncol1; i++ )
00834         {
00835             p = (double) i / ( plsc->ncol1 - 1.0 );
00836             if ( ( p < plsc->cmap1cp[n].p ) ||
00837                  ( p > plsc->cmap1cp[n + 1].p ) )
00838                 continue;
00839 
00840             // Interpolate based on position of color cell in cmap1 space
00841 
00842             delta = ( p - plsc->cmap1cp[n].p ) / dp;
00843 
00844             // Linearly interpolate to get color cell h, l, s values
00845 
00846             h = plsc->cmap1cp[n].h + dh * delta;
00847             l = plsc->cmap1cp[n].l + dl * delta;
00848             s = plsc->cmap1cp[n].s + ds * delta;
00849             a = plsc->cmap1cp[n].a + da * delta;
00850 
00851             while ( h >= 360. )
00852                 h -= 360.;
00853 
00854             while ( h < 0. )
00855                 h += 360.;
00856 
00857             c_plhlsrgb( h, l, s, &r, &g, &b );
00858 
00859             plsc->cmap1[i].r = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
00860             plsc->cmap1[i].g = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
00861             plsc->cmap1[i].b = (unsigned char) MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
00862             plsc->cmap1[i].a = a;
00863         }
00864     }
00865 
00866     if ( plsc->level > 0 )
00867         plP_state( PLSTATE_CMAP1 );
00868 }
00869 
00870 //--------------------------------------------------------------------------
00882 //--------------------------------------------------------------------------
00883 
00884 void
00885 c_plscmap1_range( PLFLT min_color, PLFLT max_color )
00886 {
00887     if ( min_color > max_color || max_color < 0.0 || min_color > 1.0 )
00888     {
00889         plwarn( "plscmap1_range called with invalid color range" );
00890         return;
00891     }
00892     if ( min_color < 0.0 )
00893     {
00894         plwarn( "plscmap1_range called with a negative minimum color value" );
00895         min_color = 0.0;
00896     }
00897     if ( max_color > 1.0 )
00898     {
00899         plwarn( "plscmap1_range called with an out of range maximum color value" );
00900         max_color = 1.0;
00901     }
00902     plsc->cmap1_min = min_color;
00903     plsc->cmap1_max = max_color;
00904 }
00905 
00906 //--------------------------------------------------------------------------
00911 //--------------------------------------------------------------------------
00912 
00913 void
00914 c_plgcmap1_range( PLFLT *min_color, PLFLT *max_color )
00915 {
00916     *min_color = plsc->cmap1_min;
00917     *max_color = plsc->cmap1_max;
00918 }
00919 
00920 //--------------------------------------------------------------------------
00921 // plscmap0n()
00922 //
00930 
00931 void
00932 c_plscmap0n( PLINT ncol0 )
00933 {
00934     int ncol, size, imin, imax;
00935 
00936 // No change
00937 
00938     if ( ncol0 > 0 && plsc->ncol0 == ncol0 )
00939         return;
00940 
00941 // Handle all possible startup conditions
00942 
00943     if ( plsc->ncol0 <= 0 && ncol0 <= 0 )
00944         ncol = 16;
00945     else if ( ncol0 <= 0 )
00946         ncol = plsc->ncol0;
00947     else
00948         ncol = ncol0;
00949 
00950     imax = ncol - 1;
00951     size = ncol * (int) sizeof ( PLColor );
00952 
00953 // Allocate the space
00954 
00955     if ( plsc->cmap0 == NULL )
00956     {
00957         if ( ( plsc->cmap0 = (PLColor *) calloc( 1, (size_t) size ) ) == NULL )
00958         {
00959             plexit( "c_plscmap0n: Insufficient memory" );
00960         }
00961         imin = 0;
00962     }
00963     else
00964     {
00965         if ( ( plsc->cmap0 = (PLColor *) realloc( plsc->cmap0, (size_t) size ) ) == NULL )
00966         {
00967             plexit( "c_plscmap0n: Insufficient memory" );
00968         }
00969         imin = plsc->ncol0;
00970     }
00971 
00972 // Fill in default entries
00973 
00974     plsc->ncol0 = ncol;
00975     plcmap0_def( imin, imax );
00976 
00977     if ( plsc->level > 0 )
00978         plP_state( PLSTATE_CMAP0 );
00979 }
00980 
00981 //--------------------------------------------------------------------------
00982 // color_set()
00983 //
00992 
00993 void
00994 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name )
00995 {
00996     plsc->cmap0[i].r    = r;
00997     plsc->cmap0[i].g    = g;
00998     plsc->cmap0[i].b    = b;
00999     plsc->cmap0[i].a    = a;
01000     plsc->cmap0[i].name = name;
01001 }
01002 
01003 #define color_def( i, r, g, b, a, n ) \
01004     if ( i >= imin && i <= imax ) color_set( i, r, g, b, a, n );
01005 
01006 //--------------------------------------------------------------------------
01007 // plcmap0_def()
01008 //
01014 
01015 void
01016 plcmap0_def( int imin, int imax )
01017 {
01018     int          i;
01019     unsigned int *r, *g, *b;
01020     double       *a;
01021     int          number_colors;
01022     if ( imin <= imax )
01023     {
01024         cmap0_palette_read( "", &number_colors, &r, &g, &b, &a );
01025         for ( i = imin; i <= MIN( ( number_colors - 1 ), imax ); i++ )
01026             color_def( i, (U_CHAR) r[i], (U_CHAR) g[i], (U_CHAR) b[i], a[i],
01027                 "colors defined by default cmap0 palette file" );
01028         free( r );
01029         free( g );
01030         free( b );
01031         free( a );
01032     }
01033     else
01034     {
01035         number_colors = 0;
01036     }
01037 
01038     // Initialize all colours undefined by the default colour palette file
01039     // to opaque red as a warning.
01040     for ( i = MAX( number_colors, imin ); i <= imax; i++ )
01041         color_def( i, 255, 0, 0, 1.0,
01042             "opaque red colour to mark not defined by palette file" );
01043 }
01044 
01045 //--------------------------------------------------------------------------
01046 // plscmap1n()
01047 //
01055 
01056 void
01057 c_plscmap1n( PLINT ncol1 )
01058 {
01059     PLINT  ncol;
01060     size_t size;
01061 
01062 // No change
01063 
01064     if ( ncol1 > 0 && plsc->ncol1 == ncol1 )
01065         return;
01066 
01067 // Handle all possible startup conditions
01068 
01069     if ( plsc->ncol1 <= 0 && ncol1 <= 0 )
01070         ncol = 128;
01071     else if ( ncol1 <= 0 )
01072         ncol = plsc->ncol1;
01073     else
01074         ncol = ncol1;
01075 
01076     size = (size_t) ncol * sizeof ( PLColor );
01077 
01078 // Allocate the space
01079 
01080     if ( plsc->ncol1 > 0 )
01081     {
01082         if ( ( plsc->cmap1 = (PLColor *) realloc( plsc->cmap1, size ) ) == NULL )
01083         {
01084             plexit( "c_plscmap1n: Insufficient memory" );
01085         }
01086     }
01087     else
01088     {
01089         if ( ( plsc->cmap1 = (PLColor *) calloc( (size_t) ncol, sizeof ( PLColor ) ) ) == NULL )
01090         {
01091             plexit( "c_plscmap1n: Insufficient memory" );
01092         }
01093     }
01094 
01095 // Fill in default entries
01096 
01097     plsc->ncol1 = ncol;
01098     if ( plsc->ncp1 == 0 )
01099         plcmap1_def();
01100     else
01101         plcmap1_calc();
01102 }
01103 
01104 //--------------------------------------------------------------------------
01105 // plcmap1_def()
01106 //
01116 
01117 void
01118 plcmap1_def( void )
01119 {
01120     PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
01121 
01122 // Positions of control points
01123 
01124     i[0] = 0;           // left boundary
01125     i[1] = 0.44;        // a little left of center
01126     i[2] = 0.50;        // at center
01127     i[3] = 0.50;        // at center
01128     i[4] = 0.56;        // a little right of center
01129     i[5] = 1;           // right boundary
01130 
01131 // For center control points, pick black or white, whichever is closer to bg
01132 // Be careful to pick just short of top or bottom else hue info is lost
01133 
01134     if ( plsc->cmap0 != NULL )
01135         vertex = ( (PLFLT) plsc->cmap0[0].r +
01136                    (PLFLT) plsc->cmap0[0].g +
01137                    (PLFLT) plsc->cmap0[0].b ) / 3. / 255.;
01138 
01139     if ( vertex < 0.5 )
01140     {
01141         vertex = 0.01;
01142         midpt  = 0.10;
01143     }
01144     else
01145     {
01146         vertex = 0.99;
01147         midpt  = 0.90;
01148     }
01149 
01150 // Set hue
01151 
01152     h[0] = 260;         // low: blue-violet
01153     h[1] = 260;         // only change as we go over vertex
01154     h[2] = 260;         // only change as we go over vertex
01155     h[3] = 0;           // high: red
01156     h[4] = 0;           // high: red
01157     h[5] = 0;           // keep fixed
01158 
01159 // Set lightness
01160 
01161     l[0] = 0.5;         // low
01162     l[1] = midpt;       // midpoint value
01163     l[2] = vertex;      // bg
01164     l[3] = vertex;      // bg
01165     l[4] = midpt;       // midpoint value
01166     l[5] = 0.5;         // high
01167 
01168 // Set saturation -- keep at maximum
01169 
01170     s[0] = 1;
01171     s[1] = 1;
01172     s[2] = 1;
01173     s[3] = 1;
01174     s[4] = 1;
01175     s[5] = 1;
01176 
01177     c_plscmap1l( 0, 6, i, h, l, s, NULL );
01178 
01179     if ( plsc->level > 0 )
01180         plP_state( PLSTATE_CMAP1 );
01181 }
01182 
01183 //--------------------------------------------------------------------------
01184 // plscolor()
01185 //
01189 //--------------------------------------------------------------------------
01190 
01191 void
01192 c_plscolor( PLINT color )
01193 {
01194     plsc->colorset = 1;
01195     plsc->color    = color;
01196 }
01197 
01198 //--------------------------------------------------------------------------
01199 // void value()
01200 //
01206 //--------------------------------------------------------------------------
01207 
01208 PLFLT
01209 value( double n1, double n2, double hue )
01210 {
01211     PLFLT val;
01212 
01213     while ( hue >= 360. )
01214         hue -= 360.;
01215     while ( hue < 0. )
01216         hue += 360.;
01217 
01218     if ( hue < 60. )
01219         val = n1 + ( n2 - n1 ) * hue / 60.;
01220     else if ( hue < 180. )
01221         val = n2;
01222     else if ( hue < 240. )
01223         val = n1 + ( n2 - n1 ) * ( 240. - hue ) / 60.;
01224     else
01225         val = n1;
01226 
01227     return ( val );
01228 }
01229 
01230 //--------------------------------------------------------------------------
01231 // void c_plhlsrgb()
01232 //
01249 
01250 void
01251 c_plhlsrgb( PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b )
01252 {
01253     PLFLT m1, m2;
01254 
01255     if ( l <= .5 )
01256         m2 = l * ( s + 1. );
01257     else
01258         m2 = l + s - l * s;
01259 
01260     m1 = 2 * l - m2;
01261 
01262     *p_r = value( m1, m2, h + 120. );
01263     *p_g = value( m1, m2, h );
01264     *p_b = value( m1, m2, h - 120. );
01265 }
01266 
01267 //--------------------------------------------------------------------------
01268 // void c_plrgbhls()
01269 //
01282 
01283 void
01284 c_plrgbhls( PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s )
01285 {
01286     PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
01287 
01288     rgb_min = MIN( r, MIN( g, b ) );
01289     rgb_max = MAX( r, MAX( g, b ) );
01290 
01291     l = ( rgb_min + rgb_max ) / 2.0;
01292 
01293     if ( rgb_min == rgb_max )
01294     {
01295         s = 0;
01296         h = 0;
01297     }
01298     else
01299     {
01300         d = rgb_max - rgb_min;
01301         if ( l < 0.5 )
01302             s = 0.5 * d / l;
01303         else
01304             s = 0.5 * d / ( 1. - l );
01305 
01306         rc = ( rgb_max - r ) / d;
01307         gc = ( rgb_max - g ) / d;
01308         bc = ( rgb_max - b ) / d;
01309 
01310         if ( r == rgb_max )
01311             h = bc - gc;
01312         else if ( g == rgb_max )
01313             h = rc - bc + 2;
01314         else
01315             h = gc - rc - 2;
01316 
01317         h = h * 60;
01318         if ( h < 0 )
01319             h = h + 360;
01320         else if ( h >= 360 )
01321             h = h - 360;
01322     }
01323     *p_h = h;
01324     *p_l = l;
01325     *p_s = s;
01326 }
01327 
01328 //--------------------------------------------------------------------------
01329 // read_line()
01330 //
01340 
01341 static char *
01342 read_line( char *buffer, int length, FILE *fp )
01343 {
01344     char *pchr;
01345 
01346     // Read the string
01347     if ( fgets( buffer, length, fp ) == NULL )
01348     {
01349         return NULL;
01350     }
01351 
01352     // Sanitize the string we read - it may contain EOL characters
01353     // Make sure file reading starts at the next line
01354     pchr = strchr( buffer, '\n' );
01355     if ( pchr != NULL )
01356     {
01357         *pchr = '\0';
01358     }
01359     else
01360     {
01361         if ( fscanf( fp, "%*[^\n]\n" ) == EOF && ferror( fp ) )
01362         {
01363             return NULL;
01364         }
01365     }
01366 
01367 
01368     pchr = strchr( buffer, '\r' );
01369     if ( pchr != NULL )
01370     {
01371         *pchr = '\0';
01372     }
01373 
01374     // Remove trailing blanks
01375     pchr = buffer + strlen( buffer ) - 1;
01376     while ( pchr != buffer && *pchr == ' ' )
01377     {
01378         *pchr = '\0';
01379         pchr--;
01380     }
01381 
01382     return buffer;
01383 }
01384 
01385 //--------------------------------------------------------------------------
01386 // cmap0_palette_read()
01387 //
01397 
01398 void
01399 cmap0_palette_read( const char *filename,
01400                     int *number_colors, unsigned int **r, unsigned int **g, unsigned int **b, double **a )
01401 {
01402     int  i, err = 0;
01403     char color_info[COLLEN];
01404     char msgbuf[MSGLEN];
01405     FILE *fp;
01406     char * save_locale = plsave_set_locale();
01407 
01408     if ( strlen( filename ) == 0 )
01409     {
01410         fp = plLibOpen( PL_DEFAULT_CMAP0_FILE );
01411         if ( fp == NULL )
01412         {
01413             snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
01414             plwarn( msgbuf );
01415             err = 1;
01416         }
01417     }
01418     else
01419     {
01420         fp = plLibOpen( filename );
01421         if ( fp == NULL )
01422         {
01423             snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", filename );
01424             plwarn( msgbuf );
01425             err = 1;
01426         }
01427     }
01428     if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) )
01429     {
01430         fclose( fp );
01431         snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 header\n" );
01432         plwarn( msgbuf );
01433         err = 1;
01434     }
01435 
01436     if ( !err )
01437     {
01438         // Allocate arrays to hold r, g, b, and a data for calling routine.
01439         // The caller must free these after it is finished with them.
01440         if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
01441              ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
01442              ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
01443              ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
01444         {
01445             fclose( fp );
01446             plexit( "cmap0_palette_read: insufficient memory" );
01447         }
01448 
01449         for ( i = 0; i < *number_colors; i++ )
01450         {
01451             if ( read_line( color_info, COLLEN, fp ) == NULL )
01452             {
01453                 err = 1;
01454                 break;
01455             }
01456 
01457             // Get the color data
01458             if ( strlen( color_info ) == 7 )
01459             {
01460                 if ( sscanf( color_info, "#%2x%2x%2x",
01461                          (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
01462                          (unsigned int *) ( *b + i ) ) != 3 )
01463                 {
01464                     err = 1;
01465                     break;
01466                 }
01467                 *( *a + i ) = 1.0;
01468             }
01469             else if ( strlen( color_info ) > 9 )
01470             {
01471                 if ( sscanf( color_info, "#%2x%2x%2x %lf",
01472                          (unsigned int *) ( *r + i ), (unsigned int *) ( *g + i ),
01473                          (unsigned int *) ( *b + i ), (double *) ( *a + i ) ) != 4 )
01474                 {
01475                     err = 1;
01476                     break;
01477                 }
01478                 // fuzzy range check.
01479                 if ( *( *a + i ) < -FUZZ_EPSILON || *( *a + i ) > ( 1. + FUZZ_EPSILON ) )
01480                 {
01481                     err = 1;
01482                     break;
01483                 }
01484                 else if ( *( *a + i ) < 0. )
01485                 {
01486                     *( *a + i ) = 0.;
01487                 }
01488                 else if ( *( *a + i ) > 1. )
01489                 {
01490                     *( *a + i ) = 1.;
01491                 }
01492             }
01493             else
01494             {
01495                 err = 1;
01496                 break;
01497             }
01498         }
01499         fclose( fp );
01500         if ( err )
01501         {
01502             snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 format data line.  Line is %s\n",
01503                 color_info );
01504             plwarn( msgbuf );
01505             free( *r );
01506             free( *g );
01507             free( *b );
01508             free( *a );
01509         }
01510     }
01511     // Fall back to opaque red on opaque white as visual warning of any
01512     // error above.
01513     if ( err )
01514     {
01515         *number_colors = 16;
01516         if ( ( ( *r = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( int ) ) ) == NULL ) ||
01517              ( ( *g = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
01518              ( ( *b = (unsigned int *) malloc( (size_t) ( *number_colors ) * sizeof ( unsigned int ) ) ) == NULL ) ||
01519              ( ( *a = (double *) malloc( (size_t) ( *number_colors ) * sizeof ( double ) ) ) == NULL ) )
01520         {
01521             plexit( "cmap0_palette_read: insufficient memory" );
01522         }
01523         **r = 255;
01524         **g = 255;
01525         **b = 255;
01526         **a = 1.;
01527         for ( i = 1; i < *number_colors; i++ )
01528         {
01529             *( *r + i ) = 255;
01530             *( *g + i ) = 0;
01531             *( *b + i ) = 0;
01532             *( *a + i ) = 1.0;
01533         }
01534     }
01535 
01536     plrestore_locale( save_locale );
01537 }
01538 
01539 //--------------------------------------------------------------------------
01540 // void c_plspal0(filename)
01541 //
01546 
01547 void
01548 c_plspal0( const char *filename )
01549 {
01550     int          i;
01551     unsigned int *r, *g, *b;
01552     double       *a;
01553     int          number_colors;
01554     cmap0_palette_read( filename, &number_colors, &r, &g, &b, &a );
01555     // Allocate default number of cmap0 colours if cmap0 allocation not
01556     // done already.
01557     plscmap0n( 0 );
01558     // Allocate sufficient cmap0 colours to contain present data.
01559     if ( number_colors > plsc->ncol0 )
01560     {
01561         plscmap0n( number_colors );
01562     }
01563     for ( i = 0; i < number_colors; i++ )
01564     {
01565         c_plscol0a( i, (PLINT) r[i], (PLINT) g[i], (PLINT) b[i], a[i] );
01566     }
01567     free( r );
01568     free( g );
01569     free( b );
01570     free( a );
01571 }
01572 
01582 #define fuzzy_range_check( value, min, max, fuzz, err_number )                                                                        \
01583     if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) {                                                                         \
01584         snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format data line.  Error number is %d. Line is %s\n", err_number, color_info ); \
01585         plwarn( msgbuf );                                                                                                             \
01586         err = 1;                                                                                                                      \
01587         break;                                                                                                                        \
01588     } else if ( value < min ) {                                                                                                       \
01589         value = min;                                                                                                                  \
01590     } else if ( value > max ) {                                                                                                       \
01591         value = max;                                                                                                                  \
01592     }
01593 
01594 //--------------------------------------------------------------------------
01595 // void c_plspal1(filename)
01596 //
01602 
01603 void
01604 c_plspal1( const char *filename, PLBOOL interpolate )
01605 {
01606     int          i;
01607     int          number_colors;
01608     int          format_version, err;
01609     PLBOOL       rgb;
01610     char         color_info[PALLEN];
01611     unsigned int r_i, g_i, b_i;
01612     int          pos_i, alt_hue_path_i;
01613     double       r_d, g_d, b_d, a_d, pos_d;
01614     PLFLT        *r, *g, *b, *a, *pos;
01615     PLINT        *ri, *gi, *bi;
01616     PLBOOL       *alt_hue_path;
01617     FILE         *fp;
01618     char         msgbuf[MSGLEN];
01619     char         * save_locale = plsave_set_locale();
01620 
01621     rgb            = TRUE;
01622     err            = 0;
01623     format_version = 0;
01624     if ( strlen( filename ) == 0 )
01625     {
01626         fp = plLibOpen( PL_DEFAULT_CMAP1_FILE );
01627         if ( fp == NULL )
01628         {
01629             snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
01630             plwarn( msgbuf );
01631             goto finish;
01632         }
01633     }
01634     else
01635     {
01636         fp = plLibOpen( filename );
01637         if ( fp == NULL )
01638         {
01639             snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", filename );
01640             plwarn( msgbuf );
01641             goto finish;
01642         }
01643     }
01644     // Check for new file format
01645     if ( read_line( color_info, PALLEN, fp ) == NULL )
01646     {
01647         snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
01648         plwarn( msgbuf );
01649         fclose( fp );
01650         goto finish;
01651     }
01652     if ( strncmp( color_info, "v2 ", 2 ) == 0 )
01653     {
01654         format_version = 1;
01655         if ( strncmp( &color_info[3], "hls", 3 ) == 0 )
01656             rgb = FALSE;
01657         else if ( strncmp( &color_info[3], "rgb", 3 ) == 0 )
01658             rgb = TRUE;
01659         else
01660         {
01661             snprintf( msgbuf, MSGLEN, "Invalid color space %s - assuming RGB\n", &color_info[3] );
01662             plwarn( msgbuf );
01663             rgb = TRUE;
01664         }
01665         if ( read_line( color_info, PALLEN, fp ) == NULL )
01666         {
01667             snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
01668             plwarn( msgbuf );
01669             fclose( fp );
01670             goto finish;
01671         }
01672     }
01673 
01674     if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 )
01675     {
01676         snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
01677         plwarn( msgbuf );
01678         fclose( fp );
01679         goto finish;
01680     }
01681 
01682     r            = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01683     g            = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01684     b            = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01685     ri           = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
01686     gi           = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
01687     bi           = (PLINT *) malloc( (size_t) number_colors * sizeof ( PLINT ) );
01688     a            = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01689     pos          = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01690     alt_hue_path = (PLBOOL *) malloc( (size_t) ( number_colors - 1 ) * sizeof ( PLBOOL ) );
01691 
01692     if ( format_version == 0 )
01693     {
01694         int return_sscanf = -1, return_sscanf_old = 0;
01695         // Old tk file format
01696         for ( i = 0; i < number_colors; i++ )
01697         {
01698             if ( read_line( color_info, PALLEN, fp ) == NULL )
01699             {
01700                 snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
01701                 plwarn( msgbuf );
01702                 fclose( fp );
01703                 goto finish;
01704             }
01705             // Ensure string is null terminated if > 160 characters
01706             color_info[PALLEN - 1] = '\0';
01707             return_sscanf          = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &alt_hue_path_i );
01708             if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) )
01709             {
01710                 snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
01711                 plwarn( msgbuf );
01712                 err = 1;
01713                 break;
01714             }
01715             return_sscanf_old = return_sscanf;
01716             // For old format, input colours range from 0 to 255 and
01717             // need to be renormalized to the range from 0. to 1..
01718             r[i]   = (PLFLT) r_i / 255.;
01719             g[i]   = (PLFLT) g_i / 255.;
01720             b[i]   = (PLFLT) b_i / 255.;
01721             a[i]   = 1.0;
01722             pos[i] = 0.01 * (PLFLT) pos_i;
01723             fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 1 );
01724             fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 2 );
01725             fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 3 );
01726             fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 4 );
01727             if ( ( return_sscanf == 5 ) && ( i != number_colors - 1 ) )
01728             {
01729                 // Next to oldest tk format with alt_hue_path specified.
01730                 alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
01731             }
01732         }
01733         if ( return_sscanf == 4 )
01734         {
01735             // Oldest tk format.  No alt_hue_path specified.
01736             free( alt_hue_path );
01737             alt_hue_path = NULL;
01738         }
01739     }
01740     else
01741     {
01742         // New floating point file version with support for alpha and alt_hue_path values
01743         for ( i = 0; i < number_colors; i++ )
01744         {
01745             if ( read_line( color_info, PALLEN, fp ) == NULL )
01746             {
01747                 snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
01748                 plwarn( msgbuf );
01749                 fclose( fp );
01750                 goto finish;
01751             }
01752             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 )
01753             {
01754                 snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
01755                 plwarn( msgbuf );
01756                 err = 1;
01757                 break;
01758             }
01759 
01760             r[i]   = (PLFLT) r_d;
01761             g[i]   = (PLFLT) g_d;
01762             b[i]   = (PLFLT) b_d;
01763             a[i]   = (PLFLT) a_d;
01764             pos[i] = (PLFLT) pos_d;
01765             // Check that all rgba and pos data within range from 0. to
01766             // 1. except for the hls colour space case where the first
01767             // coordinate is checked within range from 0. to 360.
01768             if ( rgb )
01769             {
01770                 fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 5 );
01771             }
01772             else
01773             {
01774                 fuzzy_range_check( r[i], 0., 360., ( 360. * FUZZ_EPSILON ), 6 );
01775             }
01776             fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 7 );
01777             fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 8 );
01778             fuzzy_range_check( a[i], 0., 1., FUZZ_EPSILON, 9 );
01779             fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 10 );
01780 
01781             if ( i != number_colors - 1 )
01782                 alt_hue_path[i] = (PLBOOL) alt_hue_path_i;
01783         }
01784     }
01785     fclose( fp );
01786 
01787     if ( !err )
01788     {
01789         if ( interpolate )
01790         {
01791             c_plscmap1la( rgb, number_colors, pos, r, g, b, a, alt_hue_path );
01792         }
01793         else
01794         {
01795             for ( i = 0; i < number_colors; i++ )
01796             {
01797                 ri[i] = (PLINT) ( r[i] * 255.0 );
01798                 gi[i] = (PLINT) ( g[i] * 255.0 );
01799                 bi[i] = (PLINT) ( b[i] * 255.0 );
01800             }
01801             c_plscmap1a( ri, gi, bi, a, number_colors );
01802         }
01803     }
01804     else
01805     {
01806         // Fall back to red scale as visual warning if some problem occurred
01807         // above.
01808         free( r );
01809         free( g );
01810         free( b );
01811         free( pos );
01812         number_colors = 2;
01813         r             = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01814         g             = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01815         b             = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01816         pos           = (PLFLT *) malloc( (size_t) number_colors * sizeof ( PLFLT ) );
01817         r[0]          = 0.;
01818         r[1]          = 1.;
01819         g[0]          = 0.;
01820         g[1]          = 0.;
01821         b[0]          = 0.;
01822         b[1]          = 0.;
01823         pos[0]        = 0.;
01824         pos[1]        = 1.;
01825         c_plscmap1l( TRUE, number_colors, pos, r, g, b, NULL );
01826     }
01827 
01828     free( r );
01829     free( g );
01830     free( b );
01831     free( ri );
01832     free( gi );
01833     free( bi );
01834     free( a );
01835     free( pos );
01836     free( alt_hue_path );
01837 
01838 finish: plrestore_locale( save_locale );
01839 }
01840 
01841 //--------------------------------------------------------------------------
01842 // A grab-bag of various control routines.
01843 //--------------------------------------------------------------------------
01844 
01845 //--------------------------------------------------------------------------
01846 // void plwarn()
01847 //
01851 
01852 void
01853 plwarn( const char *errormsg )
01854 {
01855     int was_gfx = 0;
01856 
01857     if ( plsc->graphx == 1 )
01858     {
01859         was_gfx = 1;
01860         pltext();
01861     }
01862 
01863     fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
01864     if ( *errormsg != '\0' )
01865         fprintf( stderr, "%s\n", errormsg );
01866 
01867     if ( was_gfx == 1 )
01868         plgra();
01869 }
01870 
01871 //--------------------------------------------------------------------------
01872 // void plabort()
01873 //
01882 
01883 void
01884 plabort( const char *errormsg )
01885 {
01886     if ( abort_handler != NULL )
01887         ( *abort_handler )( errormsg );
01888 
01889     if ( plsc->errcode != NULL )
01890         *( plsc->errcode ) = 1;
01891 
01892     if ( plsc->errmsg != NULL )
01893     {
01894         sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
01895         if ( *errormsg != '\0' )
01896             sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg );
01897     }
01898     else
01899     {
01900         int was_gfx = 0;
01901 
01902         if ( plsc->graphx == 1 )
01903         {
01904             was_gfx = 1;
01905             pltext();
01906         }
01907 
01908         fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
01909         if ( *errormsg != '\0' )
01910             fprintf( stderr, "%s, aborting operation\n", errormsg );
01911 
01912         if ( was_gfx == 1 )
01913             plgra();
01914     }
01915 }
01916 
01917 
01918 //--------------------------------------------------------------------------
01919 // void plsabort()
01920 //
01925 //--------------------------------------------------------------------------
01926 
01927 void
01928 plsabort( void ( *handler )( const char * ) )
01929 {
01930     abort_handler = handler;
01931 }
01932 
01933 //--------------------------------------------------------------------------
01934 // void plexit()
01935 //
01945 //--------------------------------------------------------------------------
01946 
01947 void
01948 plexit( const char *errormsg )
01949 {
01950     int status = 1;
01951 
01952     if ( exit_handler != NULL )
01953         status = ( *exit_handler )( errormsg );
01954 
01955     plsc->nopause = 1;
01956     if ( *errormsg != '\0' )
01957     {
01958         fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
01959         fprintf( stderr, "%s\n", errormsg );
01960     }
01961     plend();
01962 
01963     fprintf( stderr, "Program aborted\n" );
01964     exit( status );
01965 }
01966 
01967 //--------------------------------------------------------------------------
01968 // void plsexit()
01969 //
01974 //--------------------------------------------------------------------------
01975 
01976 void
01977 plsexit( int ( *handler )( const char * ) )
01978 {
01979     exit_handler = handler;
01980 }
01981 
01982 //--------------------------------------------------------------------------
01983 // void plgra()
01984 //
01990 //--------------------------------------------------------------------------
01991 
01992 void
01993 c_plgra( void )
01994 {
01995     if ( plsc->level > 0 )
01996         plP_esc( PLESC_GRAPH, NULL );
01997 }
01998 
01999 //--------------------------------------------------------------------------
02000 // void plxormod()
02001 //
02006 
02007 void
02008 c_plxormod( PLINT mode, PLINT *status )   // xor mode
02009 {
02010     static int ostate = 0;
02011 
02012     if ( !plsc->dev_xor )
02013     {
02014         *status = 0;
02015         return;
02016     }
02017 
02018     if ( plsc->level > 0 )
02019     {
02020         plP_esc( PLESC_XORMOD, &mode );
02021         if ( mode )
02022         {
02023             ostate            = plsc->plbuf_write;
02024             plsc->plbuf_write = 0;
02025         }
02026         else
02027             plsc->plbuf_write = ostate;
02028     }
02029     *status = 1;
02030 }
02031 
02032 //--------------------------------------------------------------------------
02037 void
02038 c_plsdrawmode( PLINT mode )
02039 {
02040     if ( !plsc->dev_modeset )
02041     {
02042         plwarn( "plsdrawmode: Mode setting is not supported by this device" );
02043     }
02044     else if ( plsc->level > 0 )
02045     {
02046         plP_esc( PLESC_MODESET, &mode );
02047     }
02048     else
02049     {
02050         plwarn( "plsdrawmode: Initialize PLplot first" );
02051     }
02052     return;
02053 }
02054 
02055 //--------------------------------------------------------------------------
02060 PLINT
02061 c_plgdrawmode( void )
02062 {
02063     PLINT mode;
02064 
02065     if ( !plsc->dev_modeset )
02066     {
02067         plwarn( "plgdrawmode: Mode getting is not supported by this device" );
02068         mode = PL_DRAWMODE_UNKNOWN;
02069     }
02070     else if ( plsc->level > 0 )
02071     {
02072         plP_esc( PLESC_MODEGET, &mode );
02073     }
02074     else
02075     {
02076         plwarn( "plsdrawmode: Initialize PLplot first" );
02077         mode = PL_DRAWMODE_UNKNOWN;
02078     }
02079 
02080     return ( mode );
02081 }
02082 
02083 //--------------------------------------------------------------------------
02084 // void pltext()
02085 //
02087 //--------------------------------------------------------------------------
02088 
02089 void
02090 c_pltext( void )
02091 {
02092     if ( plsc->level > 0 )
02093         plP_esc( PLESC_TEXT, NULL );
02094 }
02095 
02096 //--------------------------------------------------------------------------
02097 // void pl_cmd()
02098 //
02105 //--------------------------------------------------------------------------
02106 
02107 void
02108 pl_cmd( PLINT op, void *ptr )
02109 {
02110     plP_esc( op, ptr );
02111 }
02112 
02113 //--------------------------------------------------------------------------
02114 // char *plFindCommand
02115 //
02132 //--------------------------------------------------------------------------
02133 
02134 char *
02135 plFindCommand( const char *fn )
02136 {
02137     char *fs = NULL, *dn;
02138 
02139     //*** see if in build tree **
02140     if ( plInBuildTree() == 1 )
02141     {
02142         plGetName( BUILD_DIR, "bindings/tk", fn, &fs );
02143         if ( !plFindName( fs ) )
02144             return fs;
02145         else
02146         {
02147             plGetName( SOURCE_DIR, "scripts", fn, &fs );
02148             if ( !plFindName( fs ) )
02149                 return fs;
02150         }
02151     }
02152 
02153 // PLPLOT_BIN_ENV = $(PLPLOT_BIN)
02154 
02155 #if defined ( PLPLOT_BIN_ENV )
02156     if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL )
02157     {
02158         plGetName( dn, "", fn, &fs );
02159         if ( !plFindName( fs ) )
02160             return fs;
02161         fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); // what IS set?
02162     }
02163 #endif  // PLPLOT_BIN_ENV
02164 
02165 // Current directory
02166 
02167     plGetName( ".", "", fn, &fs );
02168     if ( !plFindName( fs ) )
02169         return fs;
02170 
02171 // PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
02172 
02173 #if defined ( PLPLOT_HOME_ENV )
02174     if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
02175     {
02176         plGetName( dn, "bin", fn, &fs );
02177         if ( !plFindName( fs ) )
02178             return fs;
02179         fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
02180     }
02181 #endif  // PLPLOT_HOME_ENV
02182 
02183 // BIN_DIR
02184 
02185 #if defined ( BIN_DIR )
02186     plGetName( BIN_DIR, "", fn, &fs );
02187     if ( !plFindName( fs ) )
02188         return fs;
02189 #endif
02190 
02191 // Crapped out
02192 
02193     free_mem( fs );
02194     fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn );
02195 #if defined ( BIN_DIR )
02196     fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" );      // what WAS set?
02197 #endif  // BIN_DIR
02198     return NULL;
02199 }
02200 
02201 //--------------------------------------------------------------------------
02202 // FILE *plLibOpen(fn)
02203 //
02215 //--------------------------------------------------------------------------
02216 
02217 FILE *
02218 plLibOpen( const char *fn )
02219 {
02220     FILE    *ret = NULL;
02221 
02222     PDFstrm *pdfs = plLibOpenPdfstrm( fn );
02223     if ( pdfs == NULL )
02224     {
02225         return NULL;
02226     }
02227     if ( pdfs->file != NULL )
02228     {
02229         ret        = pdfs->file;
02230         pdfs->file = NULL;
02231     }
02232     pdf_close( pdfs );
02233     return ret;
02234 }
02235 
02236 //--------------------------------------------------------------------------
02237 // FILE *plLibOpenPdfstrm(fn)
02238 //
02250 //--------------------------------------------------------------------------
02251 PDFstrm *
02252 plLibOpenPdfstrm( const char *fn )
02253 {
02254     PDFstrm *file;
02255     char    *fs = NULL, *dn = NULL;
02256 
02257 //***   search build tree               ***
02258 
02259     if ( plInBuildTree() == 1 )
02260     {
02261         plGetName( SOURCE_DIR, "data", fn, &fs );
02262 
02263         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02264             goto done;
02265     }
02266 
02267 //***   search PLPLOT_LIB_ENV = $(PLPLOT_LIB)   ***
02268 
02269 #if defined ( PLPLOT_LIB_ENV )
02270     if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL )
02271     {
02272         plGetName( dn, "", fn, &fs );
02273 
02274         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02275             goto done;
02276         fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); // what IS set?
02277     }
02278 #endif  // PLPLOT_LIB_ENV
02279 
02280 //***   search current directory        ***
02281 
02282     if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL )
02283     {
02284         pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn );
02285         free_mem( fs );
02286         return ( file );
02287     }
02288 
02289 //***   search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ***
02290 
02291 #if defined ( PLPLOT_HOME_ENV )
02292     if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
02293     {
02294         plGetName( dn, "lib", fn, &fs );
02295 
02296         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02297             goto done;
02298         fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); // what IS set?
02299     }
02300 #endif  // PLPLOT_HOME_ENV/lib
02301 
02302 //***   search installed location       ***
02303 
02304 #if defined ( DATA_DIR )
02305     plGetName( DATA_DIR, "", fn, &fs );
02306 
02307     if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02308         goto done;
02309 #endif  // DATA_DIR
02310 
02311 //***   search hardwired location       ***
02312 
02313 #ifdef PLLIBDEV
02314     plGetName( PLLIBDEV, "", fn, &fs );
02315 
02316     if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02317         goto done;
02318 #endif  // PLLIBDEV
02319 
02320 #ifdef macintosh
02321     file = plMacLibOpen( fn );
02322     if ( file != NULL )
02323         goto done;
02324 #endif // macintosh
02325 
02326     if ( plplotLibDir != NULL )
02327     {
02328         plGetName( plplotLibDir, "", fn, &fs );
02329         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02330             goto done;
02331     }
02332 
02333 //***   not found, give up      ***
02334     pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn );
02335     free_mem( fs );
02336     return NULL;
02337 
02338 done:
02339     pldebug( "plLibOpenPdfstr", "Found file %s\n", fs );
02340     free_mem( fs );
02341     return ( file );
02342 }
02343 
02344 //--------------------------------------------------------------------------
02345 // int plFindName
02346 //
02364 //--------------------------------------------------------------------------
02365 
02366 #ifdef __unix
02367 int
02368 plFindName( char *p )
02369 {
02370     ssize_t     n;
02371     char        buf[PLPLOT_MAX_PATH], *cp;
02372     struct stat sbuf;
02373 
02374     pldebug( "plFindName", "Trying to find %s\n", p );
02375     while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 )
02376     {
02377         pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p );
02378         if ( buf[0] == '/' )
02379         {
02380             // Link is an absolute path
02381 
02382             strncpy( p, buf, (size_t) n );
02383             p[n] = '\0';
02384             pldebug( "plFindName", "Link is absolute: %s\n", p );
02385         }
02386         else
02387         {
02388             // Link is relative to its directory; make it absolute
02389 
02390             cp = 1 + strrchr( p, '/' );
02391             strncpy( cp, buf, (size_t) n );
02392             cp[n] = '\0';
02393             pldebug( "plFindName",
02394                 "Link is relative: %s\n\tTotal path:%s\n", cp, p );
02395         }
02396     }
02397 
02398 // This macro not defined on the NEC SX-3
02399 
02400 #ifdef SX
02401 #define S_ISREG( mode )    ( mode & S_IFREG )
02402 #endif
02403 
02404 // SGI machines return ENXIO instead of EINVAL Dubois 11/92
02405 
02406     if ( errno == EINVAL || errno == ENXIO )
02407     {
02408         pldebug( "plFindName", "%s may be the one...\n", p );
02409         if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) )
02410         {
02411             pldebug( "plFindName", "%s is a regular file\n", p );
02412             return ( access( p, X_OK ) );
02413         }
02414     }
02415     pldebug( "plFindName", "%s found but is not executable\n", p );
02416     return ( errno ? errno : -1 );
02417 }
02418 
02419 #else
02420 int
02421 plFindName( char *p )
02422 {
02423     return 1;
02424 }
02425 #endif
02426 
02427 //--------------------------------------------------------------------------
02428 // void plGetName()
02429 //
02439 //--------------------------------------------------------------------------
02440 
02441 void
02442 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec )
02443 {
02444     size_t lfilespec;
02445 
02446 // Malloc space for filespec
02447 
02448     free_mem( *filespec );
02449     // Be slightly generous since 3 (two delimiters + NULL byte) should be
02450     // enough.
02451     lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10;
02452     if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL )
02453     {
02454         plexit( "plGetName: Insufficient memory" );
02455     }
02456 
02457     strcpy( *filespec, dir );
02458 
02459     if ( *subdir != '\0' )
02460     {
02461         strcat_delim( *filespec );
02462         strcat( *filespec, subdir );
02463     }
02464     if ( *filename != '\0' )
02465     {
02466         strcat_delim( *filespec );
02467         strcat( *filespec, filename );
02468     }
02469 #ifdef WIN32
02470     // According to http://msdn.microsoft.com/en-us/library/vstudio/tcxf1dw6.aspx
02471     // and also Wine tests, Microsoft does not support the c99 standard %zu
02472     // format.  Instead, %lu is recommended for size_t.
02473     pldebug( "plGetName", "Maximum length of full pathname of file to be found is %lu\n", lfilespec - 1 );
02474 #else
02475     pldebug( "plGetName", "Maximum length of full pathname of file to be found is %zu\n", lfilespec - 1 );
02476 #endif
02477     pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec );
02478 }
02479 
02480 //--------------------------------------------------------------------------
02481 // void strcat_delim()
02482 //
02487 //--------------------------------------------------------------------------
02488 
02489 void
02490 strcat_delim( char *dirspec )
02491 {
02492     size_t ldirspec = strlen( dirspec );
02493 #if defined ( MSDOS ) || defined ( WIN32 )
02494     if ( dirspec[ldirspec - 1] != '\\' )
02495         strcat( dirspec, "\\" );
02496 #elif defined ( macintosh )
02497     if ( dirspec[ldirspec - 1] != ':' )
02498         strcat( dirspec, ":" );
02499 #else           // unix is the default
02500     if ( dirspec[ldirspec - 1] != '/' )
02501         strcat( dirspec, "/" );
02502 #endif
02503 }
02504 
02505 //--------------------------------------------------------------------------
02506 // plcol_interp()
02507 //
02516 //--------------------------------------------------------------------------
02517 
02518 void
02519 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
02520 {
02521     PLFLT x, delta;
02522     int   il, ir;
02523 
02524     x     = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 );
02525     il    = (int) x;
02526     ir    = il + 1;
02527     delta = x - il;
02528 
02529     if ( ir > pls->ncol1 || il < 0 )
02530         fprintf( stderr, "Invalid color\n" );
02531 
02532     else if ( ir == pls->ncol1 || ( delta == 0. ) )
02533     {
02534         newcolor->r = pls->cmap1[il].r;
02535         newcolor->g = pls->cmap1[il].g;
02536         newcolor->b = pls->cmap1[il].b;
02537         newcolor->a = pls->cmap1[il].a;
02538     }
02539     else
02540     {
02541         newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r );
02542         newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g );
02543         newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b );
02544         newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a;
02545     }
02546 }
02547 
02548 //--------------------------------------------------------------------------
02549 // plOpenFile()
02550 //
02556 //--------------------------------------------------------------------------
02557 
02558 #define MAX_NUM_TRIES    10
02559 void
02560 plOpenFile( PLStream *pls )
02561 {
02562     int    i = 0, count = 0;
02563     size_t len;
02564     char   line[BUFFER_SIZE];
02565 
02566     while ( pls->OutFile == NULL )
02567     {
02568 // Setting pls->FileName = NULL forces creation of a new family member
02569 // You should also free the memory associated with it if you do this
02570 
02571         if ( pls->family && pls->BaseName != NULL )
02572             plP_getmember( pls );
02573 
02574 // Prompt if filename still not known
02575 
02576         if ( pls->FileName == NULL )
02577         {
02578             do
02579             {
02580                 fprintf( stdout, "Enter graphics output file name: " );
02581                 plio_fgets( line, sizeof ( line ), stdin );
02582                 len = strlen( line );
02583                 if ( len )
02584                     len--;
02585                 line[len] = '\0';       // strip new-line
02586                 count++;                // count zero entries
02587             } while ( !len && count < MAX_NUM_TRIES );
02588             plP_sfnam( pls, line );
02589         }
02590 
02591 // If name is "-", send to stdout
02592 
02593         if ( !strcmp( pls->FileName, "-" ) )
02594         {
02595             pls->OutFile     = stdout;
02596             pls->output_type = 1;
02597             break;
02598         }
02599 
02600 // Need this here again, for prompted family initialization
02601 
02602         if ( pls->family && pls->BaseName != NULL )
02603             plP_getmember( pls );
02604 
02605         if ( i++ > 10 )
02606             plexit( "Too many tries." );
02607 
02608         if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
02609             fprintf( stderr, "Can't open %s.\n", pls->FileName );
02610         else
02611             pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
02612     }
02613 }
02614 
02615 //--------------------------------------------------------------------------
02616 // plCloseFile()
02617 //
02621 //--------------------------------------------------------------------------
02622 
02623 void
02624 plCloseFile( PLStream *pls )
02625 {
02626     if ( pls->OutFile != NULL )
02627     {
02628         // Don't close if the output file was stdout
02629         if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 )
02630             return;
02631 
02632         fclose( pls->OutFile );
02633         pls->OutFile = NULL;
02634     }
02635 }
02636 
02637 //--------------------------------------------------------------------------
02638 // plP_getmember()
02639 //
02643 //--------------------------------------------------------------------------
02644 
02645 void
02646 plP_getmember( PLStream *pls )
02647 {
02648     char   tmp[BUFFER_SIZE];
02649     char   prefix[BUFFER_SIZE];
02650     char   * suffix;
02651     char   num[BUFFER_SIZE];
02652     size_t maxlen;
02653 
02654     maxlen = strlen( pls->BaseName ) + 10;
02655     if ( pls->FileName == NULL )
02656     {
02657         if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
02658         {
02659             plexit( "plP_getmember: Insufficient memory" );
02660         }
02661     }
02662 
02663     suffix = strstr( pls->BaseName, "%n" );
02664 
02665     snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen );
02666     snprintf( num, BUFFER_SIZE, tmp, pls->member );
02667 
02668     if ( suffix == NULL )
02669         snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num );
02670     else
02671     {
02672         strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 );
02673         prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0';
02674         snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 );
02675     }
02676 }
02677 
02678 //--------------------------------------------------------------------------
02679 // plP_sfnam()
02680 //
02686 //--------------------------------------------------------------------------
02687 
02688 void
02689 plP_sfnam( PLStream *pls, const char *fnam )
02690 {
02691     char   prefix[BUFFER_SIZE];
02692     char   * suffix;
02693     size_t maxlen;
02694     pls->OutFile = NULL;
02695 
02696     if ( pls->FileName != NULL )
02697         free( (void *) pls->FileName );
02698 
02699     maxlen = 10 + strlen( fnam );
02700     if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
02701     {
02702         plexit( "plP_sfnam: Insufficient memory" );
02703     }
02704 
02705     suffix = strstr( fnam, "%n" );
02706 
02707     if ( suffix == NULL )
02708     {
02709         strncpy( pls->FileName, fnam, maxlen - 1 );
02710         pls->FileName[maxlen - 1] = '\0';
02711     }
02712     else
02713     {
02714         strncpy( prefix, fnam, BUFFER_SIZE - 1 );
02715         prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0';
02716         snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 );
02717     }
02718 
02719     if ( pls->BaseName != NULL )
02720         free( (void *) pls->BaseName );
02721 
02722     if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL )
02723     {
02724         plexit( "plP_sfnam: Insufficient memory" );
02725     }
02726 
02727     strncpy( pls->BaseName, fnam, maxlen - 1 );
02728     pls->BaseName[maxlen - 1] = '\0';
02729 }
02730 
02731 //--------------------------------------------------------------------------
02732 // plFamInit()
02733 //
02737 //--------------------------------------------------------------------------
02738 
02739 void
02740 plFamInit( PLStream *pls )
02741 {
02742     if ( pls->family )
02743     {
02744         pls->bytecnt = 0;
02745         if ( !pls->member )
02746             pls->member = 1;
02747         if ( !pls->finc )
02748             pls->finc = 1;
02749         if ( !pls->fflen )
02750             pls->fflen = 1;
02751         if ( !pls->bytemax )
02752             pls->bytemax = PL_FILESIZE_KB * 1000;
02753     }
02754 }
02755 
02756 //--------------------------------------------------------------------------
02757 // plGetFam()
02758 //
02766 //--------------------------------------------------------------------------
02767 
02768 void
02769 plGetFam( PLStream *pls )
02770 {
02771     PLFLT xpmm_loc, ypmm_loc;
02772     if ( pls->family )
02773     {
02774         if ( pls->bytecnt > pls->bytemax || pls->famadv )
02775         {
02776             PLINT local_page_status = pls->page_status;
02777             plP_tidy();
02778             pls->member += pls->finc;
02779             pls->famadv  = 0;
02780             plP_init();
02781             // Restore page status (normally AT_BOP) that was changed
02782             // to AT_EOP by plP_init.
02783             pls->page_status = local_page_status;
02784 
02785             // Apply compensating factor to original xpmm and ypmm so that
02786             // character aspect ratio is preserved when overall aspect ratio
02787             // is changed.
02788             plP_gpixmm( &xpmm_loc, &ypmm_loc );
02789             plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
02790             return;
02791         }
02792     }
02793 }
02794 
02795 //--------------------------------------------------------------------------
02796 // plRotPhy()
02797 //
02810 //--------------------------------------------------------------------------
02811 
02812 void
02813 plRotPhy( PLINT orient, PLINT xmin, PLINT ymin, PLINT xmax, PLINT ymax,
02814           PLINT *px, PLINT *py )
02815 {
02816     int x, y;
02817 
02818     x = *px;
02819     y = *py;
02820 
02821     switch ( orient % 4 )
02822     {
02823     case 1:
02824         *px = xmin + ( y - ymin );
02825         *py = ymin + ( xmax - x );
02826         break;
02827 
02828     case 2:
02829         *px = xmin + ( xmax - x );
02830         *py = ymin + ( ymax - y );
02831         break;
02832 
02833     case 3:
02834         *px = xmin + ( ymax - y );
02835         *py = ymin + ( x - xmin );
02836         break;
02837 
02838     default:
02839         break;                  // do nothing
02840     }
02841 }
02842 
02843 //--------------------------------------------------------------------------
02844 // plAllocDev()
02845 //
02852 //--------------------------------------------------------------------------
02853 
02854 PLDev *
02855 plAllocDev( PLStream *pls )
02856 {
02857     if ( pls->dev != NULL )
02858         free( (void *) pls->dev );
02859 
02860     pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) );
02861     if ( pls->dev == NULL )
02862         plexit( "plAllocDev: cannot allocate memory\n" );
02863 
02864     return (PLDev *) pls->dev;
02865 }
02866 
02867 //--------------------------------------------------------------------------
02868 // plGinInit()
02869 //
02873 //--------------------------------------------------------------------------
02874 
02875 void
02876 plGinInit( PLGraphicsIn *gin )
02877 {
02878     gin->type      = 0;
02879     gin->state     = 0;
02880     gin->keysym    = 0;
02881     gin->button    = 0;
02882     gin->string[0] = '\0';
02883     gin->pX        = gin->pY = -1;
02884     gin->dX        = gin->dY = 0.;
02885     gin->wX        = gin->wY = 0.;
02886 }
02887 
02888 //--------------------------------------------------------------------------
02889 // plGetInt()
02890 //
02896 //--------------------------------------------------------------------------
02897 
02898 PLINT
02899 plGetInt( const char *s )
02900 {
02901     int  m;
02902     int  i = 0;
02903     char line[BUFFER_SIZE];
02904 
02905     while ( i++ < 10 )
02906     {
02907         fputs( s, stdout );
02908         plio_fgets( line, sizeof ( line ), stdin );
02909 
02910 #ifdef MSDOS
02911         m = atoi( line );
02912         return ( m );
02913 #else
02914         if ( sscanf( line, "%d", &m ) == 1 )
02915             return ( m );
02916         fprintf( stdout, "No value or value out of range; please try again\n" );
02917 #endif
02918     }
02919     plexit( "Too many tries." );
02920     return ( 0 );
02921 }
02922 
02923 //--------------------------------------------------------------------------
02924 // plGetFlt()
02925 //
02931 //--------------------------------------------------------------------------
02932 
02933 PLFLT
02934 plGetFlt( const char *s )
02935 {
02936     PLFLT  m;
02937     double m1;
02938     int    i = 0;
02939     char   line[BUFFER_SIZE];
02940 
02941     while ( i++ < 10 )
02942     {
02943         fputs( s, stdout );
02944         plio_fgets( line, sizeof ( line ), stdin );
02945 
02946 #ifdef MSDOS
02947         m = atof( line );
02948         return ( m );
02949 #else
02950         if ( sscanf( line, "%lf", &m1 ) == 1 )
02951         {
02952             m = (PLFLT) m1;
02953             return ( m );
02954         }
02955         fprintf( stdout, "No value or value out of range; please try again\n" );
02956 #endif
02957     }
02958     plexit( "Too many tries." );
02959     return ( 0. );
02960 }
02961 
02962 //--------------------------------------------------------------------------
02963 // plstrdup()
02964 //
02971 //--------------------------------------------------------------------------
02972 
02973 char PLDLLIMPEXP *
02974 plstrdup( const char *src )
02975 {
02976     char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) );
02977     if ( dest != NULL )
02978         strcpy( dest, src );
02979     else
02980         plabort( "Out of memory" );
02981 
02982     return dest;
02983 }
02984 
02985 #ifndef PL_HAVE_SNPRINTF
02986 //--------------------------------------------------------------------------
02987 // plsnprintf()
02988 //
02999 //--------------------------------------------------------------------------
03000 
03001 int
03002 plsnprintf( char *buffer, int n, const char *format, ... )
03003 {
03004     int     ret;
03005 
03006     va_list args;
03007     va_start( args, format );
03008     ret = vsprintf( buffer, format, args );
03009     va_end( args );
03010 
03011     // Check if overrun occured
03012     if ( ret > n - 1 )
03013         plabort( "plsnprintf: buffer overrun" );
03014 
03015     return ret;
03016 }
03017 
03018 //--------------------------------------------------------------------------
03019 // plsnscanf()
03020 //
03031 //--------------------------------------------------------------------------
03032 
03033 int
03034 plsnscanf( const char *buffer, int n, const char *format, ... )
03035 {
03036     int     ret;
03037 
03038     va_list args;
03039     va_start( args, format );
03040     ret = vsscanf( buffer, format, args );
03041     va_end( args );
03042 
03043     return ret;
03044 }
03045 
03046 #endif // PL_HAVE_SNPRINTF
03047 
03048 //--------------------------------------------------------------------------
03049 // plseed()
03050 //
03054 //--------------------------------------------------------------------------
03055 
03056 void
03057 c_plseed( unsigned int seed )
03058 {
03059     init_genrand( seed );
03060 }
03061 
03062 //--------------------------------------------------------------------------
03063 // plrandd()
03064 //
03067 //--------------------------------------------------------------------------
03068 
03069 PLFLT
03070 c_plrandd( void )
03071 {
03072     return (PLFLT) ( genrand_real1() );
03073 }
03074 
03075 //--------------------------------------------------------------------------
03076 // plsave_set_locale()
03077 //
03087 //--------------------------------------------------------------------------
03088 
03089 char *
03090 plsave_set_locale( void )
03091 {
03092     char * setlocale_ptr;
03093     char * saved_lc_numeric_locale;
03094 
03095     if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) )
03096     {
03097         plexit( "plsave_set_locale: out of memory" );
03098     }
03099 
03100     //save original LC_NUMERIC locale for restore below.
03101     if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) )
03102     {
03103         plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" );
03104     }
03105     strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 );
03106     saved_lc_numeric_locale[99] = '\0';
03107 
03108     // Do not use pldebug since get overflowed stack (infinite recursion)
03109     // if device is interactive (i.e., pls->termin is set).
03110     // comment out fprintf (unless there is some emergency debugging to do)
03111     // because output is too voluminous.
03112     //
03113     // fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
03114     //
03115 
03116     if ( !( setlocale( LC_NUMERIC, "C" ) ) )
03117     {
03118         plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" );
03119     }
03120     return saved_lc_numeric_locale;
03121 }
03122 
03123 //--------------------------------------------------------------------------
03124 // plrestore_locale()
03125 //
03131 //--------------------------------------------------------------------------
03132 
03133 void
03134 plrestore_locale( char *saved_lc_numeric_locale )
03135 {
03136     // Do not use pldebug since get overflowed stack (infinite recursion)
03137     // if device is interactive (i.e., pls->termin is set).
03138     // comment out fprintf (unless there is some emergency debugging to do)
03139     // because output is too voluminous.
03140     //
03141     // fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
03142     //
03143 
03144     if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
03145     {
03146         char msgbuf[1024];
03147         snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
03148         plexit( msgbuf );
03149     }
03150     free( saved_lc_numeric_locale );
03151 }
03152 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines