PLplot 5.9.6
plctrl.c
00001 /* $Id$
00002  *
00003  *      Misc. control routines, like begin, end, exit, change graphics/text
00004  *      mode, change color.  Includes some spillage from plcore.c.  If you
00005  *      don't know where it should go, put it here.
00006  *
00007  * Copyright (C) 2004  Joao Cardoso
00008  * Copyright (C) 2004  Rafael Laboissiere
00009  * Copyright (C) 2008  Hazen Babcock
00010  * Copyright (C) 2009  Alan W. Irwin
00011  *
00012  * This file is part of PLplot.
00013  *
00014  * PLplot is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU General Library Public License as published
00016  * by the Free Software Foundation; either version 2 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * PLplot is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU Library General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Library General Public License
00025  * along with PLplot; if not, write to the Free Software
00026  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00027  *
00028  */
00029 
00030 #define DEBUG
00031 
00032 #define NEED_PLDEBUG
00033 #include "plplotP.h"
00034 #ifdef macintosh
00035 #include "mac.h"
00036 /* for plMacLibOpen prototype; used in plLibOpen */
00037 #endif
00038 
00039 #ifdef DJGPP                    /* dos386/djgpp */
00040 #ifdef __unix
00041 #undef __unix
00042 #endif
00043 #endif
00044 
00045 #ifdef __unix
00046 #include <sys/types.h>
00047 #include <sys/stat.h>
00048 #ifdef PL_HAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 #include <errno.h>
00052 #endif
00053 
00054 /* Random number generator (Mersenne Twister) */
00055 #include "mt19937ar.h"
00056 
00057 #define BUFFER_SIZE     256
00058 
00059 /* small epsilon for fuzzy range checks that is still large enough to
00060  * work even in the single precision floating point case.*/
00061 #define FUZZ_EPSILON    1.e-4
00062 
00063 /* Static functions */
00064 
00065 /* Used by any external init code to suggest a path */
00066 char PLDLLIMPEXP * plplotLibDir = 0;
00067 
00068 static void
00069 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, char *name );
00070 
00071 static void
00072 strcat_delim( char *dirspec );
00073 
00074 static int
00075 ( *exit_handler )( const char *errormsg );
00076 
00077 static void
00078 ( *abort_handler )( const char *errormsg );
00079 
00080 static void
00081 plcmap0_def( int imin, int imax );
00082 
00083 static void
00084 plcmap1_def( void );
00085 
00086 static PLFLT
00087 value( double n1, double n2, double hue );
00088 
00089 static void
00090 cmap0_palette_read( const char *filename,
00091                     int *number_colors, int **r, int **g, int **b, double **a );
00092 /* An additional hardwired location for lib files. */
00093 /* I have no plans to change these again, ever. */
00094 
00095 #if defined ( DJGPP )
00096 #ifndef PLLIBDEV
00097 #define PLLIBDEV    "c:/plplot/lib"
00098 #endif
00099 
00100 #elif defined ( MSDOS )
00101 #ifndef PLLIBDEV
00102 #define PLLIBDEV    "c:\\plplot\\lib"
00103 #endif
00104 
00105 #else
00106 
00107 /* Anything else is assumed to be Unix */
00108 
00109 #ifndef PLLIBDEV
00110 #define PLLIBDEV    "/usr/local/plplot/lib"
00111 #endif
00112 
00113 #endif
00114 
00115 /*--------------------------------------------------------------------------*\
00116  *  Routines that deal with colors & color maps.
00117  \*--------------------------------------------------------------------------*/
00118 
00119 /*--------------------------------------------------------------------------*\
00120  * plcol0()
00121  *
00122  * Set color, map 0.  Argument is integer between 0 and plsc->ncol0.
00123  \*--------------------------------------------------------------------------*/
00124 
00125 void
00126 c_plcol0( PLINT icol0 )
00127 {
00128     if ( plsc->level < 1 )
00129     {
00130         plabort( "plcol0: Please call plinit first" );
00131         return;
00132     }
00133     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00134     {
00135         char buffer[BUFFER_SIZE];
00136         snprintf( buffer, BUFFER_SIZE, "plcol0: Invalid color map entry: %d", (int) icol0 );
00137         plabort( buffer );
00138         return;
00139     }
00140 
00141     plsc->icol0      = icol0;
00142     plsc->curcolor.r = plsc->cmap0[icol0].r;
00143     plsc->curcolor.g = plsc->cmap0[icol0].g;
00144     plsc->curcolor.b = plsc->cmap0[icol0].b;
00145     plsc->curcolor.a = plsc->cmap0[icol0].a;
00146 
00147     plsc->curcmap = 0;
00148     plP_state( PLSTATE_COLOR0 );
00149 }
00150 
00151 /*--------------------------------------------------------------------------*\
00152  * plcol1()
00153  *
00154  * Set color, map 1.  Argument is a float between 0. and 1.
00155  \*--------------------------------------------------------------------------*/
00156 
00157 void
00158 c_plcol1( PLFLT col1 )
00159 {
00160     PLINT icol1;
00161 
00162     if ( plsc->level < 1 )
00163     {
00164         plabort( "plcol1: Please call plinit first" );
00165         return;
00166     }
00167     if ( col1 < 0 || col1 > 1 || isnan( col1 ) )
00168     {
00169         char buffer[BUFFER_SIZE];
00170         snprintf( buffer, BUFFER_SIZE, "plcol1: Invalid color map position: %f", (PLFLT) col1 );
00171         plabort( buffer );
00172         return;
00173     }
00174 
00175     icol1 = (PLINT) ( col1 * plsc->ncol1 );
00176     icol1 = MIN( icol1, plsc->ncol1 - 1 );
00177 
00178     plsc->icol1      = icol1;
00179     plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
00180     plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
00181     plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
00182     plsc->curcolor.a = plsc->cmap1[plsc->icol1].a;
00183 
00184     plsc->curcmap = 1;
00185     plP_state( PLSTATE_COLOR1 );
00186 }
00187 
00188 /*--------------------------------------------------------------------------*\
00189  * plscolbg()
00190  *
00191  * Set the background color (cmap0[0]) by 8 bit RGB value
00192  \*--------------------------------------------------------------------------*/
00193 
00194 void
00195 c_plscolbg( PLINT r, PLINT g, PLINT b )
00196 {
00197     plscol0( 0, r, g, b );
00198 }
00199 
00200 /*--------------------------------------------------------------------------*\
00201  * plscolbga()
00202  *
00203  * Set the background color (cmap0[0]) by 8 bit RGB value and alpha value
00204  \*--------------------------------------------------------------------------*/
00205 
00206 void
00207 c_plscolbga( PLINT r, PLINT g, PLINT b, PLFLT a )
00208 {
00209     plscol0a( 0, r, g, b, a );
00210 }
00211 
00212 /*--------------------------------------------------------------------------*\
00213  * plgcolbg()
00214  *
00215  * Returns the background color (cmap0[0]) by 8 bit RGB value
00216  \*--------------------------------------------------------------------------*/
00217 
00218 void
00219 c_plgcolbg( PLINT *r, PLINT *g, PLINT *b )
00220 {
00221     plgcol0( 0, r, g, b );
00222 }
00223 
00224 /*--------------------------------------------------------------------------*\
00225  * plgcolbga()
00226  *
00227  * Returns the background color (cmap0[0]) by 8 bit RGB value and alpha value
00228  \*--------------------------------------------------------------------------*/
00229 
00230 void
00231 c_plgcolbga( PLINT *r, PLINT *g, PLINT *b, PLFLT *a )
00232 {
00233     plgcol0a( 0, r, g, b, a );
00234 }
00235 
00236 /*--------------------------------------------------------------------------*\
00237  * plscol0()
00238  *
00239  * Set a given color from color map 0 by 8 bit RGB value
00240  * Does not result in any additional cells to be allocated.
00241  \*--------------------------------------------------------------------------*/
00242 
00243 void
00244 c_plscol0( PLINT icol0, PLINT r, PLINT g, PLINT b )
00245 {
00246     if ( plsc->cmap0 == NULL )
00247         plscmap0n( 0 );
00248     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00249     {
00250         char buffer[BUFFER_SIZE];
00251         snprintf( buffer, BUFFER_SIZE, "plscol0: Illegal color table value: %d", (int) icol0 );
00252         plabort( buffer );
00253         return;
00254     }
00255     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) )
00256     {
00257         char buffer[BUFFER_SIZE];
00258         snprintf( buffer, BUFFER_SIZE, "plscol0: Invalid RGB color: %d, %d, %d",
00259             (int) r, (int) g, (int) b );
00260         plabort( buffer );
00261         return;
00262     }
00263 
00264     plscol0a( icol0, r, g, b, 1.0 );
00265 }
00266 
00267 /*--------------------------------------------------------------------------*\
00268  * plscol0a()
00269  *
00270  * Set a given color from color map 0 by 8 bit RGB value and alpha value.
00271  * Does not result in any additional cells to be allocated.
00272  \*--------------------------------------------------------------------------*/
00273 
00274 void
00275 c_plscol0a( PLINT icol0, PLINT r, PLINT g, PLINT b, PLFLT a )
00276 {
00277     if ( plsc->cmap0 == NULL )
00278         plscmap0n( 0 );
00279     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
00280     {
00281         char buffer[BUFFER_SIZE];
00282         snprintf( buffer, BUFFER_SIZE, "plscol0a: Illegal color table value: %d", (int) icol0 );
00283         plabort( buffer );
00284         return;
00285     }
00286     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) || ( a < 0 || a > 1.0 ) )
00287     {
00288         char buffer[BUFFER_SIZE];
00289         snprintf( buffer, BUFFER_SIZE, "plscol0a: Invalid RGB color: %d, %d, %d, %f",
00290             (int) r, (int) g, (int) b, (double) a );
00291         plabort( buffer );
00292         return;
00293     }
00294 
00295     plsc->cmap0[icol0].r = r;
00296     plsc->cmap0[icol0].g = g;
00297     plsc->cmap0[icol0].b = b;
00298     plsc->cmap0[icol0].a = a;
00299 
00300     if ( plsc->level > 0 )
00301         plP_state( PLSTATE_CMAP0 );
00302 }
00303 
00304 /*--------------------------------------------------------------------------*\
00305  * plgcol0()
00306  *
00307  * Returns 8 bit RGB values for given color from color map 0
00308  * Values are negative if an invalid color id is given
00309  \*--------------------------------------------------------------------------*/
00310 
00311 void
00312 c_plgcol0( PLINT icol0, PLINT *r, PLINT *g, PLINT *b )
00313 {
00314     if ( plsc->cmap0 == NULL )
00315         plscmap0n( 0 );
00316 
00317     *r = -1;
00318     *g = -1;
00319     *b = -1;
00320 
00321     if ( icol0 < 0 || icol0 > plsc->ncol0 )
00322     {
00323         char buffer[BUFFER_SIZE];
00324         snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
00325         plabort( buffer );
00326         return;
00327     }
00328 
00329     *r = plsc->cmap0[icol0].r;
00330     *g = plsc->cmap0[icol0].g;
00331     *b = plsc->cmap0[icol0].b;
00332 
00333     return;
00334 }
00335 
00336 /*--------------------------------------------------------------------------*\
00337  * plgcol0a()
00338  *
00339  * Returns 8 bit RGB values for given color from color map 0 and alpha value
00340  * Values are negative if an invalid color id is given
00341  \*--------------------------------------------------------------------------*/
00342 
00343 void
00344 c_plgcol0a( PLINT icol0, PLINT *r, PLINT *g, PLINT *b, PLFLT *a )
00345 {
00346     if ( plsc->cmap0 == NULL )
00347         plscmap0n( 0 );
00348 
00349     *r = -1;
00350     *g = -1;
00351     *b = -1;
00352     *a = -1.0;
00353 
00354     if ( icol0 < 0 || icol0 > plsc->ncol0 )
00355     {
00356         char buffer[BUFFER_SIZE];
00357         snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
00358         plabort( buffer );
00359         return;
00360     }
00361 
00362     *r = plsc->cmap0[icol0].r;
00363     *g = plsc->cmap0[icol0].g;
00364     *b = plsc->cmap0[icol0].b;
00365     *a = plsc->cmap0[icol0].a;
00366 
00367     return;
00368 }
00369 
00370 /*--------------------------------------------------------------------------*\
00371  * plscmap0()
00372  *
00373  * Set color map 0 colors by 8 bit RGB values.  This sets the entire color
00374  * map -- only as many colors as specified will be allocated.
00375  \*--------------------------------------------------------------------------*/
00376 
00377 void
00378 c_plscmap0( PLINT *r, PLINT *g, PLINT *b, PLINT ncol0 )
00379 {
00380     int i;
00381 
00382     plscmap0n( ncol0 );
00383 
00384     for ( i = 0; i < plsc->ncol0; i++ )
00385     {
00386         if ( ( r[i] < 0 || r[i] > 255 ) ||
00387              ( g[i] < 0 || g[i] > 255 ) ||
00388              ( b[i] < 0 || b[i] > 255 ) )
00389         {
00390             char buffer[BUFFER_SIZE];
00391             snprintf( buffer, BUFFER_SIZE, "plscmap0: Invalid RGB color: %d, %d, %d",
00392                 (int) r[i], (int) g[i], (int) b[i] );
00393             plabort( buffer );
00394             return;
00395         }
00396 
00397         plsc->cmap0[i].r = r[i];
00398         plsc->cmap0[i].g = g[i];
00399         plsc->cmap0[i].b = b[i];
00400         plsc->cmap0[i].a = 1.0;
00401     }
00402 
00403     if ( plsc->level > 0 )
00404         plP_state( PLSTATE_CMAP0 );
00405 }
00406 
00407 /*--------------------------------------------------------------------------*\
00408  * plscmap0a()
00409  *
00410  * Set color map 0 colors by 8 bit RGB and alpha value.  This sets the
00411  * entire color map -- only as many colors as specified will be allocated.
00412  \*--------------------------------------------------------------------------*/
00413 
00414 void
00415 c_plscmap0a( PLINT *r, PLINT *g, PLINT *b, PLFLT *a, PLINT ncol0 )
00416 {
00417     int i;
00418 
00419     plscmap0n( ncol0 );
00420 
00421     for ( i = 0; i < plsc->ncol0; i++ )
00422     {
00423         if ( ( r[i] < 0 || r[i] > 255 ) ||
00424              ( g[i] < 0 || g[i] > 255 ) ||
00425              ( b[i] < 0 || b[i] > 255 ) ||
00426              ( a[i] < 0.0 || a[i] > 1.0 ) )
00427         {
00428             char buffer[BUFFER_SIZE];
00429             snprintf( buffer, BUFFER_SIZE, "plscmap0a: Invalid RGB color: %d, %d, %d, %f",
00430                 (int) r[i], (int) g[i], (int) b[i], (double) a[i] );
00431             plabort( buffer );
00432             return;
00433         }
00434 
00435         plsc->cmap0[i].r = r[i];
00436         plsc->cmap0[i].g = g[i];
00437         plsc->cmap0[i].b = b[i];
00438         plsc->cmap0[i].a = a[i];
00439     }
00440 
00441     if ( plsc->level > 0 )
00442         plP_state( PLSTATE_CMAP0 );
00443 }
00444 
00445 /*--------------------------------------------------------------------------*\
00446  * plscmap1()
00447  *
00448  * Set color map 1 colors by 8 bit RGB values
00449  * This also sets the number of colors.
00450  \*--------------------------------------------------------------------------*/
00451 
00452 void
00453 c_plscmap1( PLINT *r, PLINT *g, PLINT *b, PLINT ncol1 )
00454 {
00455     int i;
00456 
00457     plscmap1n( ncol1 );
00458 
00459     for ( i = 0; i < plsc->ncol1; i++ )
00460     {
00461         if ( ( r[i] < 0 || r[i] > 255 ) ||
00462              ( g[i] < 0 || g[i] > 255 ) ||
00463              ( b[i] < 0 || b[i] > 255 ) )
00464         {
00465             char buffer[BUFFER_SIZE];
00466             snprintf( buffer, BUFFER_SIZE, "plscmap1: Invalid RGB color: %d, %d, %d",
00467                 (int) r[i], (int) g[i], (int) b[i] );
00468             plabort( buffer );
00469             return;
00470         }
00471         plsc->cmap1[i].r = r[i];
00472         plsc->cmap1[i].g = g[i];
00473         plsc->cmap1[i].b = b[i];
00474         plsc->cmap1[i].a = 1.0;
00475     }
00476 
00477     if ( plsc->level > 0 )
00478         plP_state( PLSTATE_CMAP1 );
00479 }
00480 
00481 /*--------------------------------------------------------------------------*\
00482  * plscmap1a()
00483  *
00484  * Set color map 1 colors by 8 bit RGB and alpha values
00485  * This also sets the number of colors.
00486  \*--------------------------------------------------------------------------*/
00487 
00488 void
00489 c_plscmap1a( PLINT *r, PLINT *g, PLINT *b, PLFLT *a, PLINT ncol1 )
00490 {
00491     int i;
00492 
00493     plscmap1n( ncol1 );
00494 
00495     for ( i = 0; i < plsc->ncol1; i++ )
00496     {
00497         if ( ( r[i] < 0 || r[i] > 255 ) ||
00498              ( g[i] < 0 || g[i] > 255 ) ||
00499              ( b[i] < 0 || b[i] > 255 ) ||
00500              ( a[i] < 0.0 || a[i] > 1.0 ) )
00501         {
00502             char buffer[BUFFER_SIZE];
00503             snprintf( buffer, BUFFER_SIZE, "plscmap1a: Invalid RGB color: %d, %d, %d, %f",
00504                 (int) r[i], (int) g[i], (int) b[i], (double) a[i] );
00505             plabort( buffer );
00506             return;
00507         }
00508         plsc->cmap1[i].r = r[i];
00509         plsc->cmap1[i].g = g[i];
00510         plsc->cmap1[i].b = b[i];
00511         plsc->cmap1[i].a = a[i];
00512     }
00513 
00514     if ( plsc->level > 0 )
00515         plP_state( PLSTATE_CMAP1 );
00516 }
00517 
00518 /*--------------------------------------------------------------------------*\
00519  * plscmap1l()
00520  *
00521  * Set color map 1 colors using a piece-wise linear relationship between
00522  * position in the color map (from 0 to 1) and position in HLS or RGB color
00523  * space.  May be called at any time.
00524  *
00525  * The idea here is to specify a number of control points that specify the
00526  * mapping between HLS (or RGB or CMY) and palette 1 value.  Between these
00527  * points, linear interpolation is used.  By mapping position in the color
00528  * map to function value, this gives a smooth variation of color with
00529  * intensity.  Any number of control points may be specified, located at
00530  * arbitrary positions (intensities), although typically 2 - 4 are enough.
00531  * Another way of stating this is that we are traversing a given number of
00532  * lines through HLS (or RGB) space as we move through cmap 1 entries.  The
00533  * control points at the minimum and maximum intensity (0 and 1) must
00534  * always be specified.  By adding more control points you can get more
00535  * variation.  One good technique for plotting functions that vary about
00536  * some expected average is to use an additional 2 control points in the
00537  * center (intensity ~= 0.5) that are the same color as the background
00538  * (typically white for paper output, black for crt), and same hue as the
00539  * boundary control points.  This allows the highs and lows to be very
00540  * easily distinguished.
00541  *
00542  * Each control point must specify the position in cmap 1 as well as three
00543  * coordinates in HLS or RGB space.  The first point MUST correspond to
00544  * position = 0, and the last to position = 1.
00545  *
00546  * The hue is interpolated around the "front" of the color wheel
00547  * (red<->green<->blue<->red) unless the "rev" flag is set, in which case
00548  * interpolation proceeds around the back (reverse) side.  Specifying
00549  * rev=NULL is equivalent to setting rev[]=0 for every control point.
00550  *
00551  * Bounds on RGB coordinates:
00552  *  R,G,B       [0, 1]      magnitude
00553  *
00554  * Bounds on HLS coordinates:
00555  *  hue     [0, 360]    degrees
00556  *  lightness   [0, 1]      magnitude
00557  *  saturation  [0, 1]      magnitude
00558  *
00559  * The inputs are:
00560  *  itype       0: HLS, 1: RGB
00561  *  npts        number of control points
00562  *  pos[]       position for each control point
00563  *  coord1[]    first coordinate for each control point
00564  *  coord2[]    second coordinate for each control point
00565  *  coord3[]    third coordinate for each control point
00566  *  rev[]       reverse flag for each control point
00567  \*--------------------------------------------------------------------------*/
00568 
00569 void
00570 c_plscmap1l( PLINT itype, PLINT npts, PLFLT *pos,
00571              PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLINT *rev )
00572 {
00573     int   n;
00574     PLFLT h, l, s, r, g, b;
00575 
00576     if ( npts < 2 )
00577     {
00578         plabort( "plscmap1l: Must specify at least two control points" );
00579         return;
00580     }
00581 
00582     if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) )
00583     {
00584         plabort( "plscmap1l: First, last control points must lie on boundary" );
00585         return;
00586     }
00587 
00588     if ( npts > PL_MAX_CMAP1CP )
00589     {
00590         plabort( "plscmap1l: exceeded maximum number of control points" );
00591         return;
00592     }
00593 
00594 /* Allocate if not done yet */
00595 
00596     if ( plsc->cmap1 == NULL )
00597         plscmap1n( 0 );
00598 
00599 /* Save control points */
00600 
00601     plsc->ncp1 = npts;
00602 
00603     for ( n = 0; n < npts; n++ )
00604     {
00605         if ( itype == 0 )
00606         {
00607             h = coord1[n];
00608             l = coord2[n];
00609             s = coord3[n];
00610         }
00611         else
00612         {
00613             r = coord1[n];
00614             g = coord2[n];
00615             b = coord3[n];
00616             c_plrgbhls( r, g, b, &h, &l, &s );
00617         }
00618 
00619         plsc->cmap1cp[n].h = h;
00620         plsc->cmap1cp[n].l = l;
00621         plsc->cmap1cp[n].s = s;
00622         plsc->cmap1cp[n].p = pos[n];
00623         plsc->cmap1cp[n].a = 1.0;
00624 
00625         if ( rev == NULL )
00626             plsc->cmap1cp[n].rev = 0;
00627         else
00628             plsc->cmap1cp[n].rev = rev[n];
00629     }
00630 
00631 /* Calculate and set color map */
00632 
00633     plcmap1_calc();
00634 }
00635 
00636 /*--------------------------------------------------------------------------*\
00637  * plscmap1la()
00638  *
00639  * This is the same as plscmap1l, but also allows alpha value interpolation.
00640  *
00641  \*-------------------------------------------------------------------------*/
00642 
00643 void
00644 c_plscmap1la( PLINT itype, PLINT npts, PLFLT *pos,
00645               PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLFLT *a, PLINT *rev )
00646 {
00647     int   n;
00648     PLFLT h, l, s, r, g, b;
00649 
00650     if ( npts < 2 )
00651     {
00652         plabort( "plscmap1la: Must specify at least two control points" );
00653         return;
00654     }
00655 
00656     if ( ( pos[0] != 0 ) || ( pos[npts - 1] != 1 ) )
00657     {
00658         plabort( "plscmap1la: First, last control points must lie on boundary" );
00659         return;
00660     }
00661 
00662     if ( npts > PL_MAX_CMAP1CP )
00663     {
00664         plabort( "plscmap1la: exceeded maximum number of control points" );
00665         return;
00666     }
00667 
00668 /* Allocate if not done yet */
00669 
00670     if ( plsc->cmap1 == NULL )
00671         plscmap1n( 0 );
00672 
00673 /* Save control points */
00674 
00675     plsc->ncp1 = npts;
00676 
00677     for ( n = 0; n < npts; n++ )
00678     {
00679         if ( itype == 0 )
00680         {
00681             h = coord1[n];
00682             l = coord2[n];
00683             s = coord3[n];
00684         }
00685         else
00686         {
00687             r = coord1[n];
00688             g = coord2[n];
00689             b = coord3[n];
00690             c_plrgbhls( r, g, b, &h, &l, &s );
00691         }
00692 
00693         plsc->cmap1cp[n].h = h;
00694         plsc->cmap1cp[n].l = l;
00695         plsc->cmap1cp[n].s = s;
00696         plsc->cmap1cp[n].p = pos[n];
00697         plsc->cmap1cp[n].a = a[n];
00698 
00699         if ( rev == NULL )
00700             plsc->cmap1cp[n].rev = 0;
00701         else
00702             plsc->cmap1cp[n].rev = rev[n];
00703     }
00704 
00705 /* Calculate and set color map */
00706 
00707     plcmap1_calc();
00708 }
00709 
00710 /*--------------------------------------------------------------------------*\
00711  * plcmap1_calc()
00712  *
00713  * Bin up cmap 1 space and assign colors to make inverse mapping easy.
00714  * Always do interpolation in HLS space.
00715  \*--------------------------------------------------------------------------*/
00716 
00717 void
00718 plcmap1_calc( void )
00719 {
00720     int   i, n;
00721     PLFLT delta, dp, dh, dl, ds, da;
00722     PLFLT h, l, s, p, r, g, b, a;
00723 
00724 /* Loop over all control point pairs */
00725 
00726     for ( n = 0; n < plsc->ncp1 - 1; n++ )
00727     {
00728         if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n + 1].p )
00729             continue;
00730 
00731         /* Differences in p, h, l, s between ctrl pts */
00732 
00733         dp = plsc->cmap1cp[n + 1].p - plsc->cmap1cp[n].p;
00734         dh = plsc->cmap1cp[n + 1].h - plsc->cmap1cp[n].h;
00735         dl = plsc->cmap1cp[n + 1].l - plsc->cmap1cp[n].l;
00736         ds = plsc->cmap1cp[n + 1].s - plsc->cmap1cp[n].s;
00737         da = plsc->cmap1cp[n + 1].a - plsc->cmap1cp[n].a;
00738 
00739         /* Adjust dh if we are to go around "the back side" */
00740 
00741         if ( plsc->cmap1cp[n].rev )
00742             dh = ( dh > 0 ) ? dh - 360 : dh + 360;
00743 
00744         /* Loop over all color cells.  Only interested in cells located (in */
00745         /* cmap1 space)  between n_th and n+1_th control points */
00746 
00747         for ( i = 0; i < plsc->ncol1; i++ )
00748         {
00749             p = (double) i / ( plsc->ncol1 - 1.0 );
00750             if ( ( p < plsc->cmap1cp[n].p ) ||
00751                  ( p > plsc->cmap1cp[n + 1].p ) )
00752                 continue;
00753 
00754             /* Interpolate based on position of color cell in cmap1 space */
00755 
00756             delta = ( p - plsc->cmap1cp[n].p ) / dp;
00757 
00758             /* Linearly interpolate to get color cell h, l, s values */
00759 
00760             h = plsc->cmap1cp[n].h + dh * delta;
00761             l = plsc->cmap1cp[n].l + dl * delta;
00762             s = plsc->cmap1cp[n].s + ds * delta;
00763             a = plsc->cmap1cp[n].a + da * delta;
00764 
00765             while ( h >= 360. )
00766                 h -= 360.;
00767 
00768             while ( h < 0. )
00769                 h += 360.;
00770 
00771             c_plhlsrgb( h, l, s, &r, &g, &b );
00772 
00773             plsc->cmap1[i].r = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
00774             plsc->cmap1[i].g = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
00775             plsc->cmap1[i].b = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
00776             plsc->cmap1[i].a = a;
00777         }
00778     }
00779 
00780     if ( plsc->level > 0 )
00781         plP_state( PLSTATE_CMAP1 );
00782 }
00783 
00784 /*--------------------------------------------------------------------------*\
00785  * plscmap0n()
00786  *
00787  * Set number of colors in cmap 0, (re-)allocate cmap 0, and fill with
00788  * default values for those colors not previously allocated (and less
00789  * than index 15, after that you just get grey).
00790  *
00791  * The driver is not guaranteed to support all of these.
00792  \*--------------------------------------------------------------------------*/
00793 
00794 void
00795 c_plscmap0n( PLINT ncol0 )
00796 {
00797     int ncol, size, imin, imax;
00798 
00799 /* No change */
00800 
00801     if ( ncol0 > 0 && plsc->ncol0 == ncol0 )
00802         return;
00803 
00804 /* Handle all possible startup conditions */
00805 
00806     if ( plsc->ncol0 <= 0 && ncol0 <= 0 )
00807         ncol = 16;
00808     else if ( ncol0 <= 0 )
00809         ncol = plsc->ncol0;
00810     else
00811         ncol = ncol0;
00812 
00813     imax = ncol - 1;
00814     size = ncol * sizeof ( PLColor );
00815 
00816 /* Allocate the space */
00817 
00818     if ( plsc->cmap0 == NULL )
00819     {
00820         if ( ( plsc->cmap0 = (PLColor *) calloc( 1, size ) ) == NULL )
00821         {
00822             plexit( "c_plscmap0n: Insufficient memory" );
00823         }
00824         imin = 0;
00825     }
00826     else
00827     {
00828         if ( ( plsc->cmap0 = (PLColor *) realloc( plsc->cmap0, size ) ) == NULL )
00829         {
00830             plexit( "c_plscmap0n: Insufficient memory" );
00831         }
00832         imin = plsc->ncol0;
00833     }
00834 
00835 /* Fill in default entries */
00836 
00837     plsc->ncol0 = ncol;
00838     plcmap0_def( imin, imax );
00839 
00840     if ( plsc->level > 0 )
00841         plP_state( PLSTATE_CMAP0 );
00842 }
00843 
00844 /*--------------------------------------------------------------------------*\
00845  * color_set()
00846  *
00847  * Initializes color table entry by RGB values.
00848  \*--------------------------------------------------------------------------*/
00849 
00850 void
00851 color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, char *name )
00852 {
00853     plsc->cmap0[i].r    = r;
00854     plsc->cmap0[i].g    = g;
00855     plsc->cmap0[i].b    = b;
00856     plsc->cmap0[i].a    = a;
00857     plsc->cmap0[i].name = name;
00858 }
00859 
00860 #define color_def( i, r, g, b, a, n ) \
00861     if ( i >= imin && i <= imax ) color_set( i, r, g, b, a, n );
00862 
00863 /*--------------------------------------------------------------------------*\
00864  * plcmap0_def()
00865  *
00866  * Initializes specified color map 0 color entry to its default for
00867  * index range from imin to imax.
00868  \*--------------------------------------------------------------------------*/
00869 
00870 void
00871 plcmap0_def( int imin, int imax )
00872 {
00873     int    i, *r, *g, *b;
00874     double *a;
00875     int    number_colors;
00876     if ( imin <= imax )
00877     {
00878         cmap0_palette_read( "", &number_colors, &r, &g, &b, &a );
00879         for ( i = imin; i <= MIN( ( number_colors - 1 ), imax ); i++ )
00880             color_def( i, r[i], g[i], b[i], a[i],
00881                 "colors defined by default cmap0 palette file" );
00882         free( r );
00883         free( g );
00884         free( b );
00885         free( a );
00886     }
00887     else
00888     {
00889         number_colors = 0;
00890     }
00891 
00892     /* Initialize all colours undefined by the default colour palette file
00893      * to opaque red as a warning. */
00894     for ( i = MAX( number_colors, imin ); i <= imax; i++ )
00895         color_def( i, 255, 0, 0, 1.0,
00896             "opaque red colour to mark not defined by palette file" );
00897 }
00898 
00899 /*--------------------------------------------------------------------------*\
00900  * plscmap1n()
00901  *
00902  * Set number of colors in cmap 1, (re-)allocate cmap 1, and set default
00903  * values if this is the first allocation.
00904  *
00905  * Note that the driver is allowed to disregard this number.
00906  * In particular, most use fewer than we use internally.
00907  \*--------------------------------------------------------------------------*/
00908 
00909 void
00910 c_plscmap1n( PLINT ncol1 )
00911 {
00912     int ncol, size;
00913 
00914 /* No change */
00915 
00916     if ( ncol1 > 0 && plsc->ncol1 == ncol1 )
00917         return;
00918 
00919 /* Handle all possible startup conditions */
00920 
00921     if ( plsc->ncol1 <= 0 && ncol1 <= 0 )
00922         ncol = 128;
00923     else if ( ncol1 <= 0 )
00924         ncol = plsc->ncol1;
00925     else
00926         ncol = ncol1;
00927 
00928     size = ncol * sizeof ( PLColor );
00929 
00930 /* Allocate the space */
00931 
00932     if ( plsc->ncol1 > 0 )
00933     {
00934         if ( ( plsc->cmap1 = (PLColor *) realloc( plsc->cmap1, size ) ) == NULL )
00935         {
00936             plexit( "c_plscmap1n: Insufficient memory" );
00937         }
00938     }
00939     else
00940     {
00941         if ( ( plsc->cmap1 = (PLColor *) calloc( ncol, sizeof ( PLColor ) ) ) == NULL )
00942         {
00943             plexit( "c_plscmap1n: Insufficient memory" );
00944         }
00945     }
00946 
00947 /* Fill in default entries */
00948 
00949     plsc->ncol1 = ncol;
00950     if ( plsc->ncp1 == 0 )
00951         plcmap1_def();
00952     else
00953         plcmap1_calc();
00954 }
00955 
00956 /*--------------------------------------------------------------------------*\
00957  * plcmap1_def()
00958  *
00959  * Initializes color map 1.
00960  *
00961  * The default initialization uses 6 control points in HLS space, the inner
00962  * ones being very close to one of the vertices of the HLS double cone.  The
00963  * vertex used (black or white) is chosen to be the closer to the background
00964  * color.  The 6 points were chosen over the older 4 points in order to make
00965  * weaker structures more easily visible, and give more control through the
00966  * palette editor.  If you don't like these settings.. change them!
00967  \*--------------------------------------------------------------------------*/
00968 
00969 void
00970 plcmap1_def( void )
00971 {
00972     PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
00973 
00974 /* Positions of control points */
00975 
00976     i[0] = 0;           /* left boundary */
00977     i[1] = 0.44;        /* a little left of center */
00978     i[2] = 0.50;        /* at center */
00979     i[3] = 0.50;        /* at center */
00980     i[4] = 0.56;        /* a little right of center */
00981     i[5] = 1;           /* right boundary */
00982 
00983 /* For center control points, pick black or white, whichever is closer to bg */
00984 /* Be careful to pick just short of top or bottom else hue info is lost */
00985 
00986     if ( plsc->cmap0 != NULL )
00987         vertex = ( (PLFLT) plsc->cmap0[0].r +
00988                    (PLFLT) plsc->cmap0[0].g +
00989                    (PLFLT) plsc->cmap0[0].b ) / 3. / 255.;
00990 
00991     if ( vertex < 0.5 )
00992     {
00993         vertex = 0.01;
00994         midpt  = 0.10;
00995     }
00996     else
00997     {
00998         vertex = 0.99;
00999         midpt  = 0.90;
01000     }
01001 
01002 /* Set hue */
01003 
01004     h[0] = 260;         /* low: blue-violet */
01005     h[1] = 260;         /* only change as we go over vertex */
01006     h[2] = 260;         /* only change as we go over vertex */
01007     h[3] = 0;           /* high: red */
01008     h[4] = 0;           /* high: red */
01009     h[5] = 0;           /* keep fixed */
01010 
01011 /* Set lightness */
01012 
01013     l[0] = 0.5;         /* low */
01014     l[1] = midpt;       /* midpoint value */
01015     l[2] = vertex;      /* bg */
01016     l[3] = vertex;      /* bg */
01017     l[4] = midpt;       /* midpoint value */
01018     l[5] = 0.5;         /* high */
01019 
01020 /* Set saturation -- keep at maximum */
01021 
01022     s[0] = 1;
01023     s[1] = 1;
01024     s[2] = 1;
01025     s[3] = 1;
01026     s[4] = 1;
01027     s[5] = 1;
01028 
01029     c_plscmap1l( 0, 6, i, h, l, s, NULL );
01030 
01031     if ( plsc->level > 0 )
01032         plP_state( PLSTATE_CMAP1 );
01033 }
01034 
01035 /*--------------------------------------------------------------------------*\
01036  * plscolor()
01037  *
01038  * Used to globally turn color output on/off
01039  \*--------------------------------------------------------------------------*/
01040 
01041 void
01042 c_plscolor( PLINT color )
01043 {
01044     plsc->colorset = 1;
01045     plsc->color    = color;
01046 }
01047 
01048 /*--------------------------------------------------------------------------*\
01049  * plrgb()
01050  *
01051  * Set line color by red, green, blue from  0. to 1.
01052  * Do NOT use this.  Only retained for backward compatibility
01053  \*--------------------------------------------------------------------------*/
01054 
01055 void
01056 c_plrgb( PLFLT r, PLFLT g, PLFLT b )
01057 {
01058     if ( plsc->level < 1 )
01059     {
01060         plabort( "plrgb: Please call plinit first" );
01061         return;
01062     }
01063 
01064     plsc->icol0      = PL_RGB_COLOR;
01065     plsc->curcolor.r = MAX( 0, MIN( 255, (int) ( 256. * r ) ) );
01066     plsc->curcolor.g = MAX( 0, MIN( 255, (int) ( 256. * g ) ) );
01067     plsc->curcolor.b = MAX( 0, MIN( 255, (int) ( 256. * b ) ) );
01068 
01069     plsc->curcmap = 0;
01070     plP_state( PLSTATE_COLOR0 );
01071 }
01072 
01073 /*--------------------------------------------------------------------------*\
01074  * plrgb1()
01075  *
01076  * Set line color by 8 bit RGB values.
01077  * Do NOT use this.  Only retained for backward compatibility
01078  \*--------------------------------------------------------------------------*/
01079 
01080 void
01081 c_plrgb1( PLINT r, PLINT g, PLINT b )
01082 {
01083     if ( plsc->level < 1 )
01084     {
01085         plabort( "plrgb1: Please call plinit first" );
01086         return;
01087     }
01088     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) )
01089     {
01090         plabort( "plrgb1: Invalid color" );
01091         return;
01092     }
01093 
01094     plsc->icol0      = PL_RGB_COLOR;
01095     plsc->curcolor.r = r;
01096     plsc->curcolor.g = g;
01097     plsc->curcolor.b = b;
01098 
01099     plsc->curcmap = 0;
01100     plP_state( PLSTATE_COLOR0 );
01101 }
01102 
01103 /*--------------------------------------------------------------------------*\
01104  * void plhls()
01105  *
01106  * Set current color by hue, lightness, and saturation.
01107  * Convert hls color coordinates to rgb, then call plrgb.
01108  * Do NOT use this.  Only retained for backward compatibility
01109  \*--------------------------------------------------------------------------*/
01110 
01111 void
01112 c_plhls( PLFLT h, PLFLT l, PLFLT s )
01113 {
01114     PLFLT r, g, b;
01115 
01116     c_plhlsrgb( h, l, s, &r, &g, &b );
01117     plrgb( r, g, b );
01118 }
01119 
01120 /*--------------------------------------------------------------------------*\
01121  * void value()
01122  *
01123  * Auxiliary function used by c_plhlsrgb().
01124  \*--------------------------------------------------------------------------*/
01125 
01126 PLFLT
01127 value( double n1, double n2, double hue )
01128 {
01129     PLFLT val;
01130 
01131     while ( hue >= 360. )
01132         hue -= 360.;
01133     while ( hue < 0. )
01134         hue += 360.;
01135 
01136     if ( hue < 60. )
01137         val = n1 + ( n2 - n1 ) * hue / 60.;
01138     else if ( hue < 180. )
01139         val = n2;
01140     else if ( hue < 240. )
01141         val = n1 + ( n2 - n1 ) * ( 240. - hue ) / 60.;
01142     else
01143         val = n1;
01144 
01145     return ( val );
01146 }
01147 
01148 /*--------------------------------------------------------------------------*\
01149  * void c_plhlsrgb()
01150  *
01151  * Convert HLS color to RGB color.
01152  * Bounds on HLS (input):
01153  *  hue     [0., 360.]  degrees
01154  *  lightness   [0., 1.]    magnitude
01155  *  saturation  [0., 1.]    magnitude
01156  *
01157  * Hue is always mapped onto the interval [0., 360.] regardless of input.
01158  * Bounds on RGB (output) is always [0., 1.].  Convert to RGB color values
01159  * by multiplying by 2**nbits (nbits typically 8).
01160  \*--------------------------------------------------------------------------*/
01161 
01162 void
01163 c_plhlsrgb( PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b )
01164 {
01165     PLFLT m1, m2;
01166 
01167     if ( l <= .5 )
01168         m2 = l * ( s + 1. );
01169     else
01170         m2 = l + s - l * s;
01171 
01172     m1 = 2 * l - m2;
01173 
01174     *p_r = value( m1, m2, h + 120. );
01175     *p_g = value( m1, m2, h );
01176     *p_b = value( m1, m2, h - 120. );
01177 }
01178 
01179 /*--------------------------------------------------------------------------*\
01180  * void c_plrgbhls()
01181  *
01182  * Convert RGB color to HLS color.
01183  * Bounds on RGB (input) is always [0., 1.].
01184  * Bounds on HLS (output):
01185  *  hue     [0., 360.]  degrees
01186  *  lightness   [0., 1.]    magnitude
01187  *  saturation  [0., 1.]    magnitude
01188  \*--------------------------------------------------------------------------*/
01189 
01190 void
01191 c_plrgbhls( PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s )
01192 {
01193     PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
01194 
01195     rgb_min = MIN( r, MIN( g, b ) );
01196     rgb_max = MAX( r, MAX( g, b ) );
01197 
01198     l = ( rgb_min + rgb_max ) / 2.0;
01199 
01200     if ( rgb_min == rgb_max )
01201     {
01202         s = 0;
01203         h = 0;
01204     }
01205     else
01206     {
01207         d = rgb_max - rgb_min;
01208         if ( l < 0.5 )
01209             s = 0.5 * d / l;
01210         else
01211             s = 0.5 * d / ( 1. - l );
01212 
01213         rc = ( rgb_max - r ) / d;
01214         gc = ( rgb_max - g ) / d;
01215         bc = ( rgb_max - b ) / d;
01216 
01217         if ( r == rgb_max )
01218             h = bc - gc;
01219         else if ( g == rgb_max )
01220             h = rc - bc + 2;
01221         else
01222             h = gc - rc - 2;
01223 
01224         h = h * 60;
01225         if ( h < 0 )
01226             h = h + 360;
01227         else if ( h >= 360 )
01228             h = h - 360;
01229     }
01230     *p_h = h;
01231     *p_l = l;
01232     *p_s = s;
01233 }
01234 
01235 /*--------------------------------------------------------------------------*\
01236  * cmap0_palette_read()
01237  *
01238  * Read and check r, g, b, a data from a cmap0*.pal format file.
01239  * The caller must free the returned malloc'ed space for r, g, b, and a.
01240  \*--------------------------------------------------------------------------*/
01241 
01242 void
01243 cmap0_palette_read( const char *filename,
01244                     int *number_colors, int **r, int **g, int **b, double **a )
01245 {
01246     int  i, err = 0;
01247     char color_info[30];
01248     char msgbuf[1024];
01249     FILE *fp;
01250     char * save_locale = plsave_set_locale();
01251 
01252     if ( strlen( filename ) == 0 )
01253     {
01254         fp = plLibOpen( PL_DEFAULT_CMAP0_FILE );
01255         if ( fp == NULL )
01256         {
01257             snprintf( msgbuf, 1024, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
01258             plwarn( msgbuf );
01259             err = 1;
01260         }
01261     }
01262     else
01263     {
01264         fp = plLibOpen( filename );
01265         if ( fp == NULL )
01266         {
01267             snprintf( msgbuf, 1024, "Unable to open cmap0 file %s\n", filename );
01268             plwarn( msgbuf );
01269             err = 1;
01270         }
01271     }
01272     if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) )
01273     {
01274         fclose( fp );
01275         snprintf( msgbuf, 1024, "Unrecognized cmap0 header\n" );
01276         plwarn( msgbuf );
01277         err = 1;
01278     }
01279 
01280     if ( !err )
01281     {
01282         /* Allocate arrays to hold r, g, b, and a data for calling routine.
01283          * The caller must free these after it is finished with them. */
01284         if ( ( ( *r = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01285              ( ( *g = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01286              ( ( *b = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01287              ( ( *a = (double *) malloc( *number_colors * sizeof ( double ) ) ) == NULL ) )
01288         {
01289             fclose( fp );
01290             plexit( "cmap0_palette_read: insufficient memory" );
01291         }
01292 
01293         for ( i = 0; i < *number_colors; i++ )
01294         {
01295             if ( fgets( color_info, 30, fp ) == NULL )
01296             {
01297                 err = 1;
01298                 break;
01299             }
01300             color_info[strlen( color_info ) - 1] = '\0'; /* remove return character */
01301             if ( strlen( color_info ) == 7 )
01302             {
01303                 if ( sscanf( color_info, "#%2x%2x%2x",
01304                          (int *) ( *r + i ), (int *) ( *g + i ), (int *) ( *b + i ) ) != 3 )
01305                 {
01306                     err = 1;
01307                     break;
01308                 }
01309                 *( *a + i ) = 1.0;
01310             }
01311             else if ( strlen( color_info ) > 9 )
01312             {
01313                 if ( sscanf( color_info, "#%2x%2x%2x %lf",
01314                          (int *) ( *r + i ), (int *) ( *g + i ), (int *) ( *b + i ),
01315                          (double *) ( *a + i ) ) != 4 )
01316                 {
01317                     err = 1;
01318                     break;
01319                 }
01320                 /* fuzzy range check. */
01321                 if ( *( *a + i ) < -FUZZ_EPSILON || *( *a + i ) > ( 1. + FUZZ_EPSILON ) )
01322                 {
01323                     err = 1;
01324                     break;
01325                 }
01326                 else if ( *( *a + i ) < 0. )
01327                 {
01328                     *( *a + i ) = 0.;
01329                 }
01330                 else if ( *( *a + i ) > 1. )
01331                 {
01332                     *( *a + i ) = 1.;
01333                 }
01334             }
01335             else
01336             {
01337                 err = 1;
01338                 break;
01339             }
01340         }
01341         fclose( fp );
01342         if ( err )
01343         {
01344             snprintf( msgbuf, 1024, "Unrecognized cmap0 format data line.  Line is %s\n",
01345                 color_info );
01346             plwarn( msgbuf );
01347             free( *r );
01348             free( *g );
01349             free( *b );
01350             free( *a );
01351         }
01352     }
01353     /* Fall back to opaque red on opaque white as visual warning of any
01354      * error above. */
01355     if ( err )
01356     {
01357         *number_colors = 16;
01358         if ( ( ( *r = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01359              ( ( *g = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01360              ( ( *b = (int *) malloc( *number_colors * sizeof ( int ) ) ) == NULL ) ||
01361              ( ( *a = (double *) malloc( *number_colors * sizeof ( double ) ) ) == NULL ) )
01362         {
01363             plexit( "cmap0_palette_read: insufficient memory" );
01364         }
01365         **r = 255;
01366         **g = 255;
01367         **b = 255;
01368         **a = 1.;
01369         for ( i = 1; i < *number_colors; i++ )
01370         {
01371             *( *r + i ) = 255;
01372             *( *g + i ) = 0;
01373             *( *b + i ) = 0;
01374             *( *a + i ) = 1.0;
01375         }
01376     }
01377 
01378     plrestore_locale( save_locale );
01379 }
01380 
01381 /*--------------------------------------------------------------------------*\
01382  * void c_plspal0(filename)
01383  *
01384  * Set the palette for color map 0 using a cmap0*.pal format file.
01385  * filename: the name of the cmap0*.pal file to use.
01386  \*--------------------------------------------------------------------------*/
01387 
01388 void
01389 c_plspal0( const char *filename )
01390 {
01391     int    i, *r, *g, *b;
01392     double *a;
01393     int    number_colors;
01394     cmap0_palette_read( filename, &number_colors, &r, &g, &b, &a );
01395     /* Allocate default number of cmap0 colours if cmap0 allocation not
01396      * done already. */
01397     plscmap0n( 0 );
01398     /* Allocate sufficient cmap0 colours to contain present data. */
01399     if ( number_colors > plsc->ncol0 )
01400     {
01401         plscmap0n( number_colors );
01402     }
01403     for ( i = 0; i < number_colors; i++ )
01404     {
01405         c_plscol0a( i, r[i], g[i], b[i], a[i] );
01406     }
01407     free( r );
01408     free( g );
01409     free( b );
01410     free( a );
01411 }
01412 
01413 /* This code fragment used a lot in plspal1 to deal with
01414  * floating-point range checking of a value and the adjustment of that
01415  * value when close to the range when there is floating-point errors.
01416  */
01417 #define fuzzy_range_check( value, min, max, fuzz, err_number )                                                                      \
01418     if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) {                                                                       \
01419         snprintf( msgbuf, 1024, "Unrecognized cmap1 format data line.  Error number is %d. Line is %s\n", err_number, color_info ); \
01420         plwarn( msgbuf );                                                                                                           \
01421         err = 1;                                                                                                                    \
01422         break;                                                                                                                      \
01423     } else if ( value < min ) {                                                                                                     \
01424         value = min;                                                                                                                \
01425     } else if ( value > max ) {                                                                                                     \
01426         value = max;                                                                                                                \
01427     }
01428 /*--------------------------------------------------------------------------*\
01429  * void c_plspal1(filename)
01430  *
01431  * Set the palette for color map 1 using a cmap1*.pal format file.
01432  * filename: the name of the cmap1*.pal file to use.
01433  \*--------------------------------------------------------------------------*/
01434 
01435 void
01436 c_plspal1( const char *filename, PLBOOL interpolate )
01437 {
01438     int    i;
01439     int    number_colors;
01440     int    format_version, err;
01441     PLBOOL rgb;
01442     char   color_info[160];
01443     int    r_i, g_i, b_i, pos_i, rev_i;
01444     double r_d, g_d, b_d, a_d, pos_d;
01445     PLFLT  *r, *g, *b, *a, *pos;
01446     PLINT  *ri, *gi, *bi;
01447     PLBOOL *rev;
01448     FILE   *fp;
01449     char   msgbuf[1024];
01450     char   * save_locale = plsave_set_locale();
01451 
01452     rgb            = TRUE;
01453     err            = 0;
01454     format_version = 0;
01455     if ( strlen( filename ) == 0 )
01456     {
01457         fp = plLibOpen( PL_DEFAULT_CMAP1_FILE );
01458         if ( fp == NULL )
01459         {
01460             snprintf( msgbuf, 1024, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
01461             plwarn( msgbuf );
01462             goto finish;
01463         }
01464     }
01465     else
01466     {
01467         fp = plLibOpen( filename );
01468         if ( fp == NULL )
01469         {
01470             snprintf( msgbuf, 1024, "Unable to open cmap1 .pal file %s\n", filename );
01471             plwarn( msgbuf );
01472             goto finish;
01473         }
01474     }
01475     /* Check for new file format */
01476     if ( fgets( color_info, 160, fp ) == NULL )
01477     {
01478         snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename );
01479         plwarn( msgbuf );
01480         fclose( fp );
01481         goto finish;
01482     }
01483     if ( strncmp( color_info, "v2 ", 2 ) == 0 )
01484     {
01485         format_version = 1;
01486         if ( strncmp( &color_info[3], "hls", 3 ) == 0 )
01487             rgb = FALSE;
01488         else if ( strncmp( &color_info[3], "rgb", 3 ) == 0 )
01489             rgb = TRUE;
01490         else
01491         {
01492             snprintf( msgbuf, 1024, "Invalid color space %s - assuming RGB\n", &color_info[3] );
01493             plwarn( msgbuf );
01494             rgb = TRUE;
01495         }
01496         if ( fgets( color_info, 160, fp ) == NULL )
01497         {
01498             snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename );
01499             plwarn( msgbuf );
01500             fclose( fp );
01501             goto finish;
01502         }
01503     }
01504 
01505     if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 )
01506     {
01507         snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
01508         plwarn( msgbuf );
01509         fclose( fp );
01510         goto finish;
01511     }
01512 
01513     r   = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01514     g   = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01515     b   = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01516     ri  = (PLINT *) malloc( number_colors * sizeof ( PLINT ) );
01517     gi  = (PLINT *) malloc( number_colors * sizeof ( PLINT ) );
01518     bi  = (PLINT *) malloc( number_colors * sizeof ( PLINT ) );
01519     a   = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01520     pos = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01521     rev = (PLBOOL *) malloc( number_colors * sizeof ( PLBOOL ) );
01522 
01523     if ( format_version == 0 )
01524     {
01525         int return_sscanf, return_sscanf_old = 0;
01526         /* Old tk file format */
01527         for ( i = 0; i < number_colors; i++ )
01528         {
01529             if ( fgets( color_info, 160, fp ) == NULL )
01530             {
01531                 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename );
01532                 plwarn( msgbuf );
01533                 fclose( fp );
01534                 goto finish;
01535             }
01536             /* Ensure string is null terminated if > 160 characters */
01537             color_info[159] = '\0';
01538             return_sscanf   = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &rev_i );
01539             if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) )
01540             {
01541                 snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
01542                 plwarn( msgbuf );
01543                 err = 1;
01544                 break;
01545             }
01546             return_sscanf_old = return_sscanf;
01547             /* For old format, input colours range from 0 to 255 and
01548              * need to be renormalized to the range from 0. to 1.. */
01549             r[i]   = (PLFLT) r_i / 255.;
01550             g[i]   = (PLFLT) g_i / 255.;
01551             b[i]   = (PLFLT) b_i / 255.;
01552             a[i]   = 1.0;
01553             pos[i] = 0.01 * (PLFLT) pos_i;
01554             fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 1 );
01555             fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 2 );
01556             fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 3 );
01557             fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 4 );
01558             if ( return_sscanf == 5 )
01559             {
01560                 /* Next to oldest tk format with rev specified. */
01561                 rev[i] = (PLBOOL) rev_i;
01562             }
01563         }
01564         if ( return_sscanf == 4 )
01565         {
01566             /* Oldest tk format.  No rev specified. */
01567             free( rev );
01568             rev = NULL;
01569         }
01570     }
01571     else
01572     {
01573         /* New floating point file version with support for alpha and rev values */
01574         for ( i = 0; i < number_colors; i++ )
01575         {
01576             if ( fgets( color_info, 160, fp ) == NULL )
01577             {
01578                 snprintf( msgbuf, 1024, "Error reading cmap1 .pal file %s\n", filename );
01579                 plwarn( msgbuf );
01580                 fclose( fp );
01581                 goto finish;
01582             }
01583             if ( sscanf( color_info, "%lf %lf %lf %lf %lf %d", &pos_d, &r_d, &g_d, &b_d, &a_d, &rev_i ) != 6 )
01584             {
01585                 snprintf( msgbuf, 1024, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
01586                 plwarn( msgbuf );
01587                 err = 1;
01588                 break;
01589             }
01590 
01591             r[i]   = (PLFLT) r_d;
01592             g[i]   = (PLFLT) g_d;
01593             b[i]   = (PLFLT) b_d;
01594             a[i]   = (PLFLT) a_d;
01595             pos[i] = (PLFLT) pos_d;
01596             /* Check that all rgba and pos data within range from 0. to
01597              * 1. except for the hls colour space case where the first
01598              * coordinate is checked within range from 0. to 360.*/
01599             if ( rgb )
01600             {
01601                 fuzzy_range_check( r[i], 0., 1., FUZZ_EPSILON, 5 );
01602             }
01603             else
01604             {
01605                 fuzzy_range_check( r[i], 0., 360., ( 360. * FUZZ_EPSILON ), 6 );
01606             }
01607             fuzzy_range_check( g[i], 0., 1., FUZZ_EPSILON, 7 );
01608             fuzzy_range_check( b[i], 0., 1., FUZZ_EPSILON, 8 );
01609             fuzzy_range_check( a[i], 0., 1., FUZZ_EPSILON, 9 );
01610             fuzzy_range_check( pos[i], 0., 1., FUZZ_EPSILON, 10 );
01611 
01612             rev[i] = (PLBOOL) rev_i;
01613         }
01614     }
01615     fclose( fp );
01616 
01617     if ( !err )
01618     {
01619         if ( interpolate )
01620         {
01621             c_plscmap1la( rgb, number_colors, pos, r, g, b, a, rev );
01622         }
01623         else
01624         {
01625             for ( i = 0; i < number_colors; i++ )
01626             {
01627                 ri[i] = r[i] * 255.0;
01628                 gi[i] = g[i] * 255.0;
01629                 bi[i] = b[i] * 255.0;
01630             }
01631             c_plscmap1a( ri, gi, bi, a, number_colors );
01632         }
01633     }
01634     else
01635     {
01636         /* Fall back to red scale as visual warning if some problem occurred
01637          * above. */
01638         free( r );
01639         free( g );
01640         free( b );
01641         free( pos );
01642         number_colors = 2;
01643         r             = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01644         g             = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01645         b             = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01646         pos           = (PLFLT *) malloc( number_colors * sizeof ( PLFLT ) );
01647         r[0]          = 0.;
01648         r[1]          = 1.;
01649         g[0]          = 0.;
01650         g[1]          = 0.;
01651         b[0]          = 0.;
01652         b[1]          = 0.;
01653         pos[0]        = 0.;
01654         pos[1]        = 1.;
01655         c_plscmap1l( TRUE, number_colors, pos, r, g, b, NULL );
01656     }
01657 
01658     free( r );
01659     free( g );
01660     free( b );
01661     free( ri );
01662     free( gi );
01663     free( bi );
01664     free( a );
01665     free( pos );
01666     free( rev );
01667 
01668 finish: plrestore_locale( save_locale );
01669 }
01670 
01671 /*--------------------------------------------------------------------------*\
01672  * A grab-bag of various control routines.
01673  \*--------------------------------------------------------------------------*/
01674 
01675 /*--------------------------------------------------------------------------*\
01676  * void plwarn()
01677  *
01678  * A handy way to issue warnings, if need be.
01679  \*--------------------------------------------------------------------------*/
01680 
01681 void
01682 plwarn( const char *errormsg )
01683 {
01684     int was_gfx = 0;
01685 
01686     if ( plsc->graphx == 1 )
01687     {
01688         was_gfx = 1;
01689         pltext();
01690     }
01691 
01692     fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
01693     if ( *errormsg != '\0' )
01694         fprintf( stderr, "%s\n", errormsg );
01695 
01696     if ( was_gfx == 1 )
01697         plgra();
01698 }
01699 
01700 /*--------------------------------------------------------------------------*\
01701  * void plabort()
01702  *
01703  * Much the same as plwarn(), but appends ", aborting operation" to the
01704  * error message.  Helps to keep source code uncluttered and provides a
01705  * convention for error aborts.
01706  *
01707  * If cleanup needs to be done in the main program, the user should write
01708  * his/her own exit handler and pass it in via plsabort().
01709  \*--------------------------------------------------------------------------*/
01710 
01711 void
01712 plabort( const char *errormsg )
01713 {
01714     if ( abort_handler != NULL )
01715         ( *abort_handler )( errormsg );
01716 
01717     if ( plsc->errcode != NULL )
01718         *( plsc->errcode ) = 1;
01719 
01720     if ( plsc->errmsg != NULL )
01721     {
01722         sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
01723         if ( *errormsg != '\0' )
01724             sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg );
01725     }
01726     else
01727     {
01728         int was_gfx = 0;
01729 
01730         if ( plsc->graphx == 1 )
01731         {
01732             was_gfx = 1;
01733             pltext();
01734         }
01735 
01736         fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
01737         if ( *errormsg != '\0' )
01738             fprintf( stderr, "%s, aborting operation\n", errormsg );
01739 
01740         if ( was_gfx == 1 )
01741             plgra();
01742     }
01743 }
01744 
01745 
01746 /*--------------------------------------------------------------------------*\
01747  * void plsabort()
01748  *
01749  * Sets an optional user abort handler.
01750  \*--------------------------------------------------------------------------*/
01751 
01752 void
01753 plsabort( void ( *handler )( const char * ) )
01754 {
01755     abort_handler = handler;
01756 }
01757 
01758 /*--------------------------------------------------------------------------*\
01759  * void plexit()
01760  *
01761  * In case of an abort this routine is called.  It just prints out an error
01762  * message and tries to clean up as much as possible.  It's best to turn
01763  * off pause and then restore previous setting before returning.
01764  *
01765  * If cleanup needs to be done in the main program, the user should write
01766  * his/her own exit handler and pass it in via plsexit().  This function
01767  * should should either call plend() before exiting, or simply return.
01768  \*--------------------------------------------------------------------------*/
01769 
01770 void
01771 plexit( const char *errormsg )
01772 {
01773     int status = 1;
01774 
01775     if ( exit_handler != NULL )
01776         status = ( *exit_handler )( errormsg );
01777 
01778     plsc->nopause = 1;
01779     if ( *errormsg != '\0' )
01780     {
01781         fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
01782         fprintf( stderr, "%s\n", errormsg );
01783     }
01784     plend();
01785 
01786     fprintf( stderr, "Program aborted\n" );
01787     exit( status );
01788 }
01789 
01790 /*--------------------------------------------------------------------------*\
01791  * void plsexit()
01792  *
01793  * Sets an optional user exit handler.
01794  \*--------------------------------------------------------------------------*/
01795 
01796 void
01797 plsexit( int ( *handler )( const char * ) )
01798 {
01799     exit_handler = handler;
01800 }
01801 
01802 /*--------------------------------------------------------------------------*\
01803  * void plgra()
01804  *
01805  * Switches to graphics screen.
01806  *
01807  * Here and in pltext() it's a good idea to return silently if plinit()
01808  * hasn't yet been called, since plwarn() calls pltext() and plgra(), and
01809  * plwarn() may be called at any time.
01810  \*--------------------------------------------------------------------------*/
01811 
01812 void
01813 c_plgra( void )
01814 {
01815     if ( plsc->level > 0 )
01816         plP_esc( PLESC_GRAPH, NULL );
01817 }
01818 
01819 void
01820 c_plxormod( PLINT mode, PLINT *status )   /* xor mode */
01821 {
01822     static int ostate = 0;
01823 
01824     if ( !plsc->dev_xor )
01825     {
01826         *status = 0;
01827         return;
01828     }
01829 
01830     if ( plsc->level > 0 )
01831     {
01832         plP_esc( PLESC_XORMOD, &mode );
01833         if ( mode )
01834         {
01835             ostate            = plsc->plbuf_write;
01836             plsc->plbuf_write = 0;
01837         }
01838         else
01839             plsc->plbuf_write = ostate;
01840     }
01841     *status = 1;
01842 }
01843 
01844 /*--------------------------------------------------------------------------*\
01845  * void pltext()
01846  *
01847  * Switches to text screen.
01848  \*--------------------------------------------------------------------------*/
01849 
01850 void
01851 c_pltext( void )
01852 {
01853     if ( plsc->level > 0 )
01854         plP_esc( PLESC_TEXT, NULL );
01855 }
01856 
01857 /*--------------------------------------------------------------------------*\
01858  * void pl_cmd()
01859  *
01860  * Front-end to driver escape function.
01861  * In principle this can be used to pass just about anything directly
01862  * to the driver.
01863  \*--------------------------------------------------------------------------*/
01864 
01865 void
01866 pl_cmd( PLINT op, void *ptr )
01867 {
01868     plP_esc( op, ptr );
01869 }
01870 
01871 /*--------------------------------------------------------------------------*\
01872  * char *plFindCommand
01873  *
01874  * Looks for the specified executable file.  Search path:
01875  *      if command invoked in the build tree:
01876  *         build_tree/tk (plserver lies there - needed for the tk driver)
01877  *         source_tree/scripts (plpr lies there - needed for the tk driver)
01878  *      else
01879  *  PLPLOT_BIN_ENV = $(PLPLOT_BIN)
01880  *  current directory
01881  *  PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
01882  *  BIN_DIR
01883  *
01884  * The caller must free the returned pointer (points to malloc'ed memory)
01885  * when finished with it.
01886  \*--------------------------------------------------------------------------*/
01887 
01888 char *
01889 plFindCommand( const char *fn )
01890 {
01891     char *fs = NULL, *dn;
01892 
01893     /**** see if in build tree ***/
01894     if ( plInBuildTree() == 1 )
01895     {
01896         plGetName( BUILD_DIR, "bindings/tk", fn, &fs );
01897         if ( !plFindName( fs ) )
01898             return fs;
01899         else
01900         {
01901             plGetName( SOURCE_DIR, "scripts", fn, &fs );
01902             if ( !plFindName( fs ) )
01903                 return fs;
01904         }
01905     }
01906 
01907 /* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */
01908 
01909 #if defined ( PLPLOT_BIN_ENV )
01910     if ( ( dn = getenv( PLPLOT_BIN_ENV ) ) != NULL )
01911     {
01912         plGetName( dn, "", fn, &fs );
01913         if ( !plFindName( fs ) )
01914             return fs;
01915         fprintf( stderr, PLPLOT_BIN_ENV "=\"%s\"\n", dn ); /* what IS set? */
01916     }
01917 #endif  /* PLPLOT_BIN_ENV */
01918 
01919 /* Current directory */
01920 
01921     plGetName( ".", "", fn, &fs );
01922     if ( !plFindName( fs ) )
01923         return fs;
01924 
01925 /* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */
01926 
01927 #if defined ( PLPLOT_HOME_ENV )
01928     if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
01929     {
01930         plGetName( dn, "bin", fn, &fs );
01931         if ( !plFindName( fs ) )
01932             return fs;
01933         fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); /* what IS set? */
01934     }
01935 #endif  /* PLPLOT_HOME_ENV */
01936 
01937 /* BIN_DIR */
01938 
01939 #if defined ( BIN_DIR )
01940     plGetName( BIN_DIR, "", fn, &fs );
01941     if ( !plFindName( fs ) )
01942         return fs;
01943 #endif
01944 
01945 /* Crapped out */
01946 
01947     free_mem( fs );
01948     fprintf( stderr, "plFindCommand: cannot locate command: %s\n", fn );
01949 #if defined ( BIN_DIR )
01950     fprintf( stderr, "bin dir=\"" BIN_DIR "\"\n" );      /* what WAS set? */
01951 #endif  /* BIN_DIR */
01952     return NULL;
01953 }
01954 
01955 /*--------------------------------------------------------------------------*\
01956  * FILE *plLibOpen(fn)
01957  *
01958  * Return file pointer to lib file.
01959  * Locations checked:
01960  *  PLPLOT_LIB_ENV = $(PLPLOT_LIB)
01961  *  current directory
01962  *  PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib
01963  *  DATA_DIR
01964  *  PLLIBDEV
01965  \*--------------------------------------------------------------------------*/
01966 
01967 FILE *
01968 plLibOpen( const char *fn )
01969 {
01970     FILE    *ret = NULL;
01971 
01972     PDFstrm *pdfs = plLibOpenPdfstrm( fn );
01973     if ( pdfs == NULL )
01974     {
01975         return NULL;
01976     }
01977     if ( pdfs->file != NULL )
01978     {
01979         ret        = pdfs->file;
01980         pdfs->file = NULL;
01981     }
01982     pdf_close( pdfs );
01983     return ret;
01984 }
01985 
01986 PDFstrm *
01987 plLibOpenPdfstrm( const char *fn )
01988 {
01989     PDFstrm *file;
01990     char    *fs = NULL, *dn = NULL;
01991 
01992 /****   search build tree               ****/
01993 
01994     if ( plInBuildTree() == 1 )
01995     {
01996         plGetName( SOURCE_DIR, "data", fn, &fs );
01997 
01998         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
01999             goto done;
02000     }
02001 
02002 /****   search PLPLOT_LIB_ENV = $(PLPLOT_LIB)   ****/
02003 
02004 #if defined ( PLPLOT_LIB_ENV )
02005     if ( ( dn = getenv( PLPLOT_LIB_ENV ) ) != NULL )
02006     {
02007         plGetName( dn, "", fn, &fs );
02008 
02009         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02010             goto done;
02011         fprintf( stderr, PLPLOT_LIB_ENV "=\"%s\"\n", dn ); /* what IS set? */
02012     }
02013 #endif  /* PLPLOT_LIB_ENV */
02014 
02015 /****   search current directory    ****/
02016 
02017     if ( ( file = pdf_fopen( fn, "rb" ) ) != NULL )
02018     {
02019         pldebug( "plLibOpenPdfstr", "Found file %s in current directory.\n", fn );
02020         free_mem( fs );
02021         return ( file );
02022     }
02023 
02024 /****   search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ****/
02025 
02026 #if defined ( PLPLOT_HOME_ENV )
02027     if ( ( dn = getenv( PLPLOT_HOME_ENV ) ) != NULL )
02028     {
02029         plGetName( dn, "lib", fn, &fs );
02030 
02031         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02032             goto done;
02033         fprintf( stderr, PLPLOT_HOME_ENV "=\"%s\"\n", dn ); /* what IS set? */
02034     }
02035 #endif  /* PLPLOT_HOME_ENV/lib */
02036 
02037 /****   search installed location   ****/
02038 
02039 #if defined ( DATA_DIR )
02040     plGetName( DATA_DIR, "", fn, &fs );
02041 
02042     if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02043         goto done;
02044 #endif  /* DATA_DIR */
02045 
02046 /****   search hardwired location   ****/
02047 
02048 #ifdef PLLIBDEV
02049     plGetName( PLLIBDEV, "", fn, &fs );
02050 
02051     if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02052         goto done;
02053 #endif  /* PLLIBDEV */
02054 
02055 #ifdef macintosh
02056     file = plMacLibOpen( fn );
02057     if ( file != NULL )
02058         goto done;
02059 #endif /* macintosh */
02060 
02061     if ( plplotLibDir != NULL )
02062     {
02063         plGetName( plplotLibDir, "", fn, &fs );
02064         if ( ( file = pdf_fopen( fs, "rb" ) ) != NULL )
02065             goto done;
02066     }
02067 
02068 /****   not found, give up      ****/
02069     pldebug( "plLibOpenPdfstr", "File %s not found.\n", fn );
02070     free_mem( fs );
02071     return NULL;
02072 
02073 done:
02074     pldebug( "plLibOpenPdfstr", "Found file %s\n", fs );
02075     free_mem( fs );
02076     return ( file );
02077 }
02078 
02079 /*--------------------------------------------------------------------------*\
02080  * int plFindName
02081  *
02082  * Authors: Paul Dubois (LLNL), others?
02083  * This function is in the public domain.
02084  *
02085  * Given a pathname, determine if it is a symbolic link.  If so, continue
02086  * searching to the ultimate terminus - there may be more than one link.
02087  * Use the error value to determine when the terminus is reached, and to
02088  * determine if the pathname really exists.  Then stat it to determine
02089  * whether it's executable.  Return 0 for an executable, errno otherwise.
02090  * Note that 'p' _must_ have at least one '/' character - it does by
02091  * construction in this program.  The contents of the array pointed to by
02092  * 'p' are changed to the actual pathname if findname is successful.
02093  *
02094  * This function is only defined under Unix for now.
02095  \*--------------------------------------------------------------------------*/
02096 
02097 #ifdef __unix
02098 int
02099 plFindName( char *p )
02100 {
02101     int         n;
02102     char        buf[PLPLOT_MAX_PATH], *cp;
02103     extern int  errno;
02104     struct stat sbuf;
02105 
02106     pldebug( "plFindName", "Trying to find %s\n", p );
02107     while ( ( n = readlink( p, buf, PLPLOT_MAX_PATH ) ) > 0 )
02108     {
02109         pldebug( "plFindName", "Readlink read %d chars at: %s\n", n, p );
02110         if ( buf[0] == '/' )
02111         {
02112             /* Link is an absolute path */
02113 
02114             strncpy( p, buf, n );
02115             p[n] = '\0';
02116             pldebug( "plFindName", "Link is absolute: %s\n", p );
02117         }
02118         else
02119         {
02120             /* Link is relative to its directory; make it absolute */
02121 
02122             cp = 1 + strrchr( p, '/' );
02123             strncpy( cp, buf, n );
02124             cp[n] = '\0';
02125             pldebug( "plFindName",
02126                 "Link is relative: %s\n\tTotal path:%s\n", cp, p );
02127         }
02128     }
02129 
02130 /* This macro not defined on the NEC SX-3 */
02131 
02132 #ifdef SX
02133 #define S_ISREG( mode )    ( mode & S_IFREG )
02134 #endif
02135 
02136 /* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */
02137 
02138     if ( errno == EINVAL || errno == ENXIO )
02139     {
02140         pldebug( "plFindName", "%s may be the one...\n", p );
02141         if ( ( stat( p, &sbuf ) == 0 ) && S_ISREG( sbuf.st_mode ) )
02142         {
02143             pldebug( "plFindName", "%s is a regular file\n", p );
02144             return ( access( p, X_OK ) );
02145         }
02146     }
02147     pldebug( "plFindName", "%s found but is not executable\n", p );
02148     return ( errno ? errno : -1 );
02149 }
02150 
02151 #else
02152 int
02153 plFindName( char *p )
02154 {
02155     return 1;
02156 }
02157 #endif
02158 
02159 /*--------------------------------------------------------------------------*\
02160  * void plGetName()
02161  *
02162  * Gets search name for file by concatenating the dir, subdir, and file
02163  * name, allocating memory as needed.  The appropriate delimiter is added
02164  * after the dir specification as necessary.  The caller is responsible
02165  * for freeing the malloc'ed memory.
02166  \*--------------------------------------------------------------------------*/
02167 
02168 void
02169 plGetName( const char *dir, const char *subdir, const char *filename, char **filespec )
02170 {
02171     int lfilespec;
02172 
02173 /* Malloc space for filespec */
02174 
02175     free_mem( *filespec );
02176     lfilespec = strlen( dir ) + strlen( subdir ) + strlen( filename ) + 10;
02177     if ( ( *filespec = (char *) malloc( lfilespec ) ) == NULL )
02178     {
02179         plexit( "plGetName: Insufficient memory" );
02180     }
02181 
02182     strcpy( *filespec, dir );
02183 
02184     if ( *subdir != '\0' )
02185     {
02186         strcat_delim( *filespec );
02187         strcat( *filespec, subdir );
02188     }
02189     if ( *filename != '\0' )
02190     {
02191         strcat_delim( *filespec );
02192         strcat( *filespec, filename );
02193     }
02194     pldebug( "plGetName", "Length of full pathname of file to be found is %d\n", lfilespec );
02195     pldebug( "plGetName", "Full pathname of file to be found is %s\n", *filespec );
02196 }
02197 
02198 /*--------------------------------------------------------------------------*\
02199  * void strcat_delim()
02200  *
02201  * Append path name deliminator if necessary (does not add one if one's
02202  * there already, or if dealing with a colon-terminated device name).
02203  \*--------------------------------------------------------------------------*/
02204 
02205 void
02206 strcat_delim( char *dirspec )
02207 {
02208     int ldirspec = strlen( dirspec );
02209 #if defined ( MSDOS ) || defined ( WIN32 )
02210     if ( dirspec[ldirspec - 1] != '\\' )
02211         strcat( dirspec, "\\" );
02212 #elif defined ( macintosh )
02213     if ( dirspec[ldirspec - 1] != ':' )
02214         strcat( dirspec, ":" );
02215 #else           /* unix is the default */
02216     if ( dirspec[ldirspec - 1] != '/' )
02217         strcat( dirspec, "/" );
02218 #endif
02219 }
02220 
02221 /*--------------------------------------------------------------------------*\
02222  * plcol_interp()
02223  *
02224  * Initializes device cmap 1 entry by interpolation from pls->cmap1
02225  * entries.  Returned PLColor is supposed to represent the i_th color
02226  * out of a total of ncol colors in the current color scheme.
02227  \*--------------------------------------------------------------------------*/
02228 
02229 void
02230 plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
02231 {
02232     PLFLT x, delta;
02233     int   il, ir;
02234 
02235     x     = (double) ( i * ( pls->ncol1 - 1 ) ) / (double) ( ncol - 1 );
02236     il    = (int) x;
02237     ir    = il + 1;
02238     delta = x - il;
02239 
02240     if ( ir > pls->ncol1 || il < 0 )
02241         fprintf( stderr, "Invalid color\n" );
02242 
02243     else if ( ir == pls->ncol1 || ( delta == 0. ) )
02244     {
02245         newcolor->r = pls->cmap1[il].r;
02246         newcolor->g = pls->cmap1[il].g;
02247         newcolor->b = pls->cmap1[il].b;
02248         newcolor->a = pls->cmap1[il].a;
02249     }
02250     else
02251     {
02252         newcolor->r = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].r + delta * pls->cmap1[ir].r );
02253         newcolor->g = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].g + delta * pls->cmap1[ir].g );
02254         newcolor->b = (unsigned char) ( ( 1. - delta ) * pls->cmap1[il].b + delta * pls->cmap1[ir].b );
02255         newcolor->a = ( 1. - delta ) * pls->cmap1[il].a + delta * pls->cmap1[ir].a;
02256     }
02257 }
02258 
02259 /*--------------------------------------------------------------------------*\
02260  * plOpenFile()
02261  *
02262  * Opens file for output, prompting if not set.
02263  * Prints extra newline at end to make output look better in batch runs.
02264  * A file name of "-" indicates output to stdout.
02265  \*--------------------------------------------------------------------------*/
02266 
02267 #define MAX_NUM_TRIES    10
02268 void
02269 plOpenFile( PLStream *pls )
02270 {
02271     int    i = 0, count = 0;
02272     size_t len;
02273     char   line[BUFFER_SIZE];
02274 
02275     while ( pls->OutFile == NULL )
02276     {
02277 /* Setting pls->FileName = NULL forces creation of a new family member */
02278 /* You should also free the memory associated with it if you do this */
02279 
02280         if ( pls->family && pls->BaseName != NULL )
02281             plP_getmember( pls );
02282 
02283 /* Prompt if filename still not known */
02284 
02285         if ( pls->FileName == NULL )
02286         {
02287             do
02288             {
02289                 fprintf( stdout, "Enter graphics output file name: " );
02290                 plio_fgets( line, sizeof ( line ), stdin );
02291                 len = strlen( line );
02292                 if ( len )
02293                     len--;
02294                 line[len] = '\0';       /* strip new-line */
02295                 count++;                /* count zero entries */
02296             } while ( !len && count < MAX_NUM_TRIES );
02297             plP_sfnam( pls, line );
02298         }
02299 
02300 /* If name is "-", send to stdout */
02301 
02302         if ( !strcmp( pls->FileName, "-" ) )
02303         {
02304             pls->OutFile     = stdout;
02305             pls->output_type = 1;
02306             break;
02307         }
02308 
02309 /* Need this here again, for prompted family initialization */
02310 
02311         if ( pls->family && pls->BaseName != NULL )
02312             plP_getmember( pls );
02313 
02314         if ( i++ > 10 )
02315             plexit( "Too many tries." );
02316 
02317         if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
02318             fprintf( stderr, "Can't open %s.\n", pls->FileName );
02319         else
02320             pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
02321     }
02322 }
02323 
02324 /*--------------------------------------------------------------------------*\
02325  * plCloseFile()
02326  *
02327  * Closes output file unless it is associated with stdout.
02328  \*--------------------------------------------------------------------------*/
02329 
02330 void
02331 plCloseFile( PLStream *pls )
02332 {
02333     if ( pls->OutFile != NULL )
02334     {
02335         /* Don't close if the output file was stdout */
02336         if ( pls->FileName && strcmp( pls->FileName, "-" ) == 0 )
02337             return;
02338 
02339         fclose( pls->OutFile );
02340         pls->OutFile = NULL;
02341     }
02342 }
02343 
02344 /*--------------------------------------------------------------------------*\
02345  * plP_getmember()
02346  *
02347  * Sets up next file member name (in pls->FileName), but does not open it.
02348  \*--------------------------------------------------------------------------*/
02349 
02350 void
02351 plP_getmember( PLStream *pls )
02352 {
02353     char tmp[BUFFER_SIZE];
02354     char prefix[BUFFER_SIZE];
02355     char * suffix;
02356     char num[BUFFER_SIZE];
02357     int  maxlen;
02358 
02359     maxlen = strlen( pls->BaseName ) + 10;
02360     if ( pls->FileName == NULL )
02361     {
02362         if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
02363         {
02364             plexit( "plP_getmember: Insufficient memory" );
02365         }
02366     }
02367 
02368     suffix = strstr( pls->BaseName, "%n" );
02369 
02370     snprintf( tmp, BUFFER_SIZE, "%%0%1ii", (int) pls->fflen );
02371     snprintf( num, BUFFER_SIZE, tmp, pls->member );
02372 
02373     if ( suffix == NULL )
02374         snprintf( pls->FileName, maxlen, "%s.%s", pls->BaseName, num );
02375     else
02376     {
02377         strncpy( prefix, pls->BaseName, BUFFER_SIZE - 1 );
02378         prefix [( suffix - pls->BaseName < BUFFER_SIZE ) ? ( suffix - pls->BaseName ) : BUFFER_SIZE - 1] = '\0';
02379         snprintf( pls->FileName, maxlen, "%s%s%s", prefix, num, suffix + 2 );
02380     }
02381 }
02382 
02383 /*--------------------------------------------------------------------------*\
02384  * plP_sfnam()
02385  *
02386  * Sets up file name (with "%n" removed if present) & family stem name.
02387  * Reserve some extra space (10 chars) to hold an optional member number.
02388  \*--------------------------------------------------------------------------*/
02389 
02390 void
02391 plP_sfnam( PLStream *pls, const char *fnam )
02392 {
02393     char prefix[BUFFER_SIZE];
02394     char * suffix;
02395     int  maxlen;
02396     pls->OutFile = NULL;
02397 
02398     if ( pls->FileName != NULL )
02399         free( (void *) pls->FileName );
02400 
02401     maxlen = 10 + strlen( fnam );
02402     if ( ( pls->FileName = (char *) malloc( maxlen ) ) == NULL )
02403     {
02404         plexit( "plP_sfnam: Insufficient memory" );
02405     }
02406 
02407     suffix = strstr( fnam, "%n" );
02408 
02409     if ( suffix == NULL )
02410     {
02411         strncpy( pls->FileName, fnam, maxlen - 1 );
02412         pls->FileName[maxlen - 1] = '\0';
02413     }
02414     else
02415     {
02416         strncpy( prefix, fnam, BUFFER_SIZE - 1 );
02417         prefix [( suffix - fnam ) < BUFFER_SIZE ? ( suffix - fnam ) : BUFFER_SIZE - 1] = '\0';
02418         snprintf( pls->FileName, maxlen, "%s%s", prefix, suffix + 2 );
02419     }
02420 
02421     if ( pls->BaseName != NULL )
02422         free( (void *) pls->BaseName );
02423 
02424     if ( ( pls->BaseName = (char *) malloc( maxlen ) ) == NULL )
02425     {
02426         plexit( "plP_sfnam: Insufficient memory" );
02427     }
02428 
02429     strncpy( pls->BaseName, fnam, maxlen - 1 );
02430     pls->BaseName[maxlen - 1] = '\0';
02431 }
02432 
02433 /*--------------------------------------------------------------------------*\
02434  * plFamInit()
02435  *
02436  * Initializes family file parameters.
02437  \*--------------------------------------------------------------------------*/
02438 
02439 void
02440 plFamInit( PLStream *pls )
02441 {
02442     if ( pls->family )
02443     {
02444         pls->bytecnt = 0;
02445         if ( !pls->member )
02446             pls->member = 1;
02447         if ( !pls->finc )
02448             pls->finc = 1;
02449         if ( !pls->fflen )
02450             pls->fflen = 1;
02451         if ( !pls->bytemax )
02452             pls->bytemax = PL_FILESIZE_KB * 1000;
02453     }
02454 }
02455 
02456 /*--------------------------------------------------------------------------*\
02457  * plGetFam()
02458  *
02459  * Starts new member file of family file set if necessary.
02460  *
02461  * Note each member file is a complete graphics file (can be printed
02462  * individually), although 'plrender' will treat a family as a single
02463  * logical file if given the family name instead of the member name.
02464  \*--------------------------------------------------------------------------*/
02465 
02466 void
02467 plGetFam( PLStream *pls )
02468 {
02469     PLFLT xpmm_loc, ypmm_loc;
02470     if ( pls->family )
02471     {
02472         if ( pls->bytecnt > pls->bytemax || pls->famadv )
02473         {
02474             PLINT local_page_status = pls->page_status;
02475             plP_tidy();
02476             pls->member += pls->finc;
02477             pls->famadv  = 0;
02478             plP_init();
02479             /* Restore page status (normally AT_BOP) that was changed
02480              * to AT_EOP by plP_init. */
02481             pls->page_status = local_page_status;
02482 
02483             /* Apply compensating factor to original xpmm and ypmm so that
02484              * character aspect ratio is preserved when overall aspect ratio
02485              * is changed. */
02486             plP_gpixmm( &xpmm_loc, &ypmm_loc );
02487             plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
02488             return;
02489         }
02490     }
02491 }
02492 
02493 /*--------------------------------------------------------------------------*\
02494  * plRotPhy()
02495  *
02496  * Rotates physical coordinates if necessary for given orientation.
02497  * Each time orient is incremented, the plot is rotated 90 deg clockwise.
02498  * Note: this is now used only to rotate by 90 degrees for devices that
02499  * expect portrait mode.
02500  \*--------------------------------------------------------------------------*/
02501 
02502 void
02503 plRotPhy( PLINT orient, PLINT xmin, PLINT ymin, PLINT xmax, PLINT ymax,
02504           PLINT *px, PLINT *py )
02505 {
02506     int x, y;
02507 
02508     x = *px;
02509     y = *py;
02510 
02511     switch ( orient % 4 )
02512     {
02513     case 1:
02514         *px = xmin + ( y - ymin );
02515         *py = ymin + ( xmax - x );
02516         break;
02517 
02518     case 2:
02519         *px = xmin + ( xmax - x );
02520         *py = ymin + ( ymax - y );
02521         break;
02522 
02523     case 3:
02524         *px = xmin + ( ymax - y );
02525         *py = ymin + ( x - xmin );
02526         break;
02527 
02528     default:
02529         break;                  /* do nothing */
02530     }
02531 }
02532 
02533 /*--------------------------------------------------------------------------*\
02534  * plAllocDev()
02535  *
02536  * Allocates a standard PLDev structure for device-specific data, stores
02537  * the address in pls->dev, and returns the address as well.
02538  \*--------------------------------------------------------------------------*/
02539 
02540 PLDev *
02541 plAllocDev( PLStream *pls )
02542 {
02543     if ( pls->dev != NULL )
02544         free( (void *) pls->dev );
02545 
02546     pls->dev = calloc( 1, (size_t) sizeof ( PLDev ) );
02547     if ( pls->dev == NULL )
02548         plexit( "plAllocDev: cannot allocate memory\n" );
02549 
02550     return (PLDev *) pls->dev;
02551 }
02552 
02553 /*--------------------------------------------------------------------------*\
02554  * plGinInit()
02555  *
02556  * Just fills in the PLGraphicsIn with appropriate initial values.
02557  \*--------------------------------------------------------------------------*/
02558 
02559 void
02560 plGinInit( PLGraphicsIn *gin )
02561 {
02562     gin->type      = 0;
02563     gin->state     = 0;
02564     gin->keysym    = 0;
02565     gin->button    = 0;
02566     gin->string[0] = '\0';
02567     gin->pX        = gin->pY = -1;
02568     gin->dX        = gin->dY = 0.;
02569     gin->wX        = gin->wY = 0.;
02570 }
02571 
02572 /*--------------------------------------------------------------------------*\
02573  * plGetInt()
02574  *
02575  * Prompts human to input an integer in response to given message.
02576  \*--------------------------------------------------------------------------*/
02577 
02578 PLINT
02579 plGetInt( const char *s )
02580 {
02581     int  m;
02582     int  i = 0;
02583     char line[BUFFER_SIZE];
02584 
02585     while ( i++ < 10 )
02586     {
02587         fputs( s, stdout );
02588         plio_fgets( line, sizeof ( line ), stdin );
02589 
02590 #ifdef MSDOS
02591         m = atoi( line );
02592         return ( m );
02593 #else
02594         if ( sscanf( line, "%d", &m ) == 1 )
02595             return ( m );
02596         fprintf( stdout, "No value or value out of range; please try again\n" );
02597 #endif
02598     }
02599     plexit( "Too many tries." );
02600     return ( 0 );
02601 }
02602 
02603 /*--------------------------------------------------------------------------*\
02604  * plGetFlt()
02605  *
02606  * Prompts human to input a float in response to given message.
02607  \*--------------------------------------------------------------------------*/
02608 
02609 PLFLT
02610 plGetFlt( const char *s )
02611 {
02612     PLFLT  m;
02613     double m1;
02614     int    i = 0;
02615     char   line[BUFFER_SIZE];
02616 
02617     while ( i++ < 10 )
02618     {
02619         fputs( s, stdout );
02620         plio_fgets( line, sizeof ( line ), stdin );
02621 
02622 #ifdef MSDOS
02623         m = atof( line );
02624         return ( m );
02625 #else
02626         if ( sscanf( line, "%lf", &m1 ) == 1 )
02627         {
02628             m = (PLFLT) m1;
02629             return ( m );
02630         }
02631         fprintf( stdout, "No value or value out of range; please try again\n" );
02632 #endif
02633     }
02634     plexit( "Too many tries." );
02635     return ( 0. );
02636 }
02637 
02638 /*--------------------------------------------------------------------------*\
02639  * plstrdup()
02640  *
02641  * A replacement for strdup(), which isn't portable.
02642  * Caller responsible for freeing the allocated memory.
02643  \*--------------------------------------------------------------------------*/
02644 
02645 char PLDLLIMPEXP *
02646 plstrdup( const char *src )
02647 {
02648     char *dest = (char *) malloc( ( strlen( src ) + 1 ) * sizeof ( char ) );
02649     if ( dest != NULL )
02650         strcpy( dest, src );
02651     else
02652         plabort( "Out of memory" );
02653 
02654     return dest;
02655 }
02656 
02657 #ifndef PL_HAVE_SNPRINTF
02658 /*--------------------------------------------------------------------------*\
02659  * plsnprintf()
02660  *
02661  * Dummy function for snprintf(). This function just calls
02662  * the unsafe function ignoring the string size. This function will
02663  * rarely be needed if ever.
02664  \*--------------------------------------------------------------------------*/
02665 
02666 int
02667 plsnprintf( char *buffer, int n, const char *format, ... )
02668 {
02669     int     ret;
02670 
02671     va_list args;
02672     va_start( args, format );
02673     ret = vsprintf( buffer, fmt, args );
02674     va_end( argptr );
02675 
02676     /* Check if overrun occured */
02677     if ( ret > n - 1 )
02678         plabort( "plsnprintf: buffer overrun" );
02679 
02680     return ret;
02681 }
02682 
02683 /*--------------------------------------------------------------------------*\
02684  * plsnscanf()
02685  *
02686  * Dummy function for snscanf(). This function just calls
02687  * the unsafe function ignoring the string size. This function will
02688  * rarely be needed if ever.
02689  \*--------------------------------------------------------------------------*/
02690 
02691 int
02692 plsnscanf( const char *buffer, int n, const char *format, ... )
02693 {
02694     int     ret;
02695 
02696     va_list argptr;
02697     va_start( argptr, format );
02698     ret = vsscanf( buffer, fmt, args );
02699     va_end( argptr );
02700 
02701     return ret;
02702 }
02703 
02704 #endif /* PL_HAVE_SNPRINTF */
02705 
02706 /*--------------------------------------------------------------------------*\
02707  * plseed()
02708  *
02709  * Set the seed for the random number generator included.
02710  \*--------------------------------------------------------------------------*/
02711 
02712 void
02713 c_plseed( unsigned int s )
02714 {
02715     init_genrand( s );
02716 }
02717 
02718 /*--------------------------------------------------------------------------*\
02719  * plrandd()
02720  *
02721  * Returns a random number on [0,1]-interval.
02722  \*--------------------------------------------------------------------------*/
02723 
02724 PLFLT
02725 c_plrandd( void )
02726 {
02727     return (PLFLT) ( genrand_real1() );
02728 }
02729 
02730 /*--------------------------------------------------------------------------*\
02731  * plsave_set_locale()
02732  *
02733  * Save LC_NUMERIC locale in a string.  The pointer to that string is
02734  * returned. Then set LC_NUMERIC to "C" locale.
02735  * n.b. plsave_set_locale and plrestore_locale should always be used as
02736  * a pair to surround PLplot code that absolutely requires the
02737  * LC_NUMERIC "C" locale to be in effect.  It is one of plrestore_locale's
02738  * responsibilities to free the memory allocated here for the locale
02739  * string.
02740  \*--------------------------------------------------------------------------*/
02741 
02742 char *
02743 plsave_set_locale( void )
02744 {
02745     char * setlocale_ptr;
02746     char * saved_lc_numeric_locale;
02747 
02748     if ( !( saved_lc_numeric_locale = (char *) malloc( 100 * sizeof ( char ) ) ) )
02749     {
02750         plexit( "plsave_set_locale: out of memory" );
02751     }
02752 
02753     /*save original LC_NUMERIC locale for restore below. */
02754     if ( !( setlocale_ptr = setlocale( LC_NUMERIC, NULL ) ) )
02755     {
02756         plexit( "plsave_set_locale: LC_NUMERIC locale could not be determined for NULL locale.\n" );
02757     }
02758     strncpy( saved_lc_numeric_locale, setlocale_ptr, 100 );
02759     saved_lc_numeric_locale[99] = '\0';
02760 
02761     /* Do not use pldebug since get overflowed stack (infinite recursion)
02762      * if device is interactive (i.e., pls->termin is set). */
02763     /* comment out fprintf (unless there is some emergency debugging to do)
02764      * because output is too voluminous. */
02765     /*
02766      * fprintf(stderr, "plsave_set_locale: saved LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
02767      */
02768 
02769     if ( !( setlocale( LC_NUMERIC, "C" ) ) )
02770     {
02771         plexit( "plsave_set_locale: LC_NUMERIC locale could not be set to \"C\"" );
02772     }
02773     return saved_lc_numeric_locale;
02774 }
02775 
02776 /*--------------------------------------------------------------------------*\
02777  * plrestore_locale()
02778  *
02779  * Restore LC_NUMERIC locale string that was determined by
02780  * plsave_set_locale with the pointer to that string as the argument.
02781  * Also, free the memory for that string.
02782  \*--------------------------------------------------------------------------*/
02783 
02784 void
02785 plrestore_locale( char *saved_lc_numeric_locale )
02786 {
02787     /* Do not use pldebug since get overflowed stack (infinite recursion)
02788      * if device is interactive (i.e., pls->termin is set). */
02789     /* comment out fprintf (unless there is some emergency debugging to do)
02790      * because output is too voluminous. */
02791     /*
02792      * fprintf(stderr, "plrestore_locale: restored LC_NUMERIC locale is \"%s\"\n", saved_lc_numeric_locale);
02793      */
02794 
02795     if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
02796     {
02797         char msgbuf[1024];
02798         snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
02799         plexit( msgbuf );
02800     }
02801     free( saved_lc_numeric_locale );
02802 }
02803 
 All Data Structures Files Functions