• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plctrl.c

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

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1