PLplot  5.10.0
plbuf.c
Go to the documentation of this file.
00001 //  Handle plot buffer.
00002 //
00003 //  Copyright (C) 1992  Maurice LeBrun
00004 //  Copyright (C) 2004-2014 Alan W. Irwin
00005 //  Copyright (C) 2005  Thomas J. Duck
00006 //  Copyright (C) 2006  Jim Dishaw
00007 //
00008 //  This file is part of PLplot.
00009 //
00010 //  PLplot is free software; you can redistribute it and/or modify
00011 //  it under the terms of the GNU Library General Public License as published
00012 //  by the Free Software Foundation; either version 2 of the License, or
00013 //  (at your option) any later version.
00014 //
00015 //  PLplot is distributed in the hope that it will be useful,
00016 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 //  GNU Library General Public License for more details.
00019 //
00020 //  You should have received a copy of the GNU Library General Public License
00021 //  along with PLplot; if not, write to the Free Software
00022 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 
00025 #define NEED_PLDEBUG
00026 #include "plplotP.h"
00027 #include "drivers.h"
00028 #include "metadefs.h"
00029 
00030 #include <string.h>
00031 
00032 // Function prototypes
00033 void * plbuf_save( PLStream *pls, void *state );
00034 
00035 static int      rd_command( PLStream *pls, U_CHAR *p_c );
00036 static void     rd_data( PLStream *pls, void *buf, size_t buf_size );
00037 static void     wr_command( PLStream *pls, U_CHAR c );
00038 static void     wr_data( PLStream *pls, void *buf, size_t buf_size );
00039 static void     plbuf_control( PLStream *pls, U_CHAR c );
00040 
00041 static void     rdbuf_init( PLStream *pls );
00042 static void     rdbuf_line( PLStream *pls );
00043 static void     rdbuf_polyline( PLStream *pls );
00044 static void     rdbuf_eop( PLStream *pls );
00045 static void     rdbuf_bop( PLStream *pls );
00046 static void     rdbuf_state( PLStream *pls );
00047 static void     rdbuf_esc( PLStream *pls );
00048 
00049 static void     plbuf_fill( PLStream *pls );
00050 static void     rdbuf_fill( PLStream *pls );
00051 static void     plbuf_swin( PLStream *pls, PLWindow *plwin );
00052 static void     rdbuf_swin( PLStream *pls );
00053 
00054 //--------------------------------------------------------------------------
00055 // plbuf_init()
00056 //
00057 // Initialize device.
00058 // Actually just disables writes if plot buffer is already open (occurs
00059 // when one stream is cloned, as in printing).
00060 //--------------------------------------------------------------------------
00061 
00062 void
00063 plbuf_init( PLStream *pls )
00064 {
00065     dbug_enter( "plbuf_init" );
00066 
00067     pls->plbuf_read = FALSE;
00068 #ifdef BUFFERED_FILE
00069     if ( pls->plbufFile != NULL )
00070         pls->plbuf_write = FALSE;
00071 #else
00072     if ( pls->plbuf_buffer != NULL )
00073         pls->plbuf_write = FALSE;
00074 #endif
00075 }
00076 
00077 //--------------------------------------------------------------------------
00078 // plbuf_line()
00079 //
00080 // Draw a line in the current color from (x1,y1) to (x2,y2).
00081 //--------------------------------------------------------------------------
00082 
00083 void
00084 plbuf_line( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
00085 {
00086     short xpl[2], ypl[2];
00087 
00088     dbug_enter( "plbuf_line" );
00089 
00090     wr_command( pls, (U_CHAR) LINE );
00091 
00092     xpl[0] = x1a;
00093     xpl[1] = x2a;
00094     ypl[0] = y1a;
00095     ypl[1] = y2a;
00096 
00097     wr_data( pls, xpl, sizeof ( short ) * 2 );
00098     wr_data( pls, ypl, sizeof ( short ) * 2 );
00099 }
00100 
00101 //--------------------------------------------------------------------------
00102 // plbuf_polyline()
00103 //
00104 // Draw a polyline in the current color.
00105 //--------------------------------------------------------------------------
00106 
00107 void
00108 plbuf_polyline( PLStream *pls, short *xa, short *ya, PLINT npts )
00109 {
00110     dbug_enter( "plbuf_polyline" );
00111 
00112     wr_command( pls, (U_CHAR) POLYLINE );
00113 
00114     wr_data( pls, &npts, sizeof ( PLINT ) );
00115 
00116     wr_data( pls, xa, sizeof ( short ) * (size_t) npts );
00117     wr_data( pls, ya, sizeof ( short ) * (size_t) npts );
00118 }
00119 
00120 //--------------------------------------------------------------------------
00121 // plbuf_eop()
00122 //
00123 // End of page.
00124 //--------------------------------------------------------------------------
00125 
00126 void
00127 plbuf_eop( PLStream * PL_UNUSED( pls ) )
00128 {
00129     dbug_enter( "plbuf_eop" );
00130 }
00131 
00132 //--------------------------------------------------------------------------
00133 // plbuf_bop()
00134 //
00135 // Set up for the next page.
00136 // To avoid problems redisplaying partially filled pages, on each BOP the
00137 // old file is thrown away and a new one is obtained.  This way we can just
00138 // read up to EOF to get everything on the current page.
00139 //
00140 // Also write state information to ensure the next page is correct.
00141 //--------------------------------------------------------------------------
00142 
00143 void
00144 plbuf_bop( PLStream *pls )
00145 {
00146     dbug_enter( "plbuf_bop" );
00147 
00148     plbuf_tidy( pls );
00149 
00150 #ifdef BUFFERED_FILE
00151     pls->plbufFile = pl_create_tempfile( NULL );
00152     if ( pls->plbufFile == NULL )
00153         plexit( "plbuf_bop: Error opening plot data storage file." );
00154 #else
00155     // Need a better place to initialize this value
00156     pls->plbuf_buffer_grow = 128 * 1024;
00157 
00158     if ( pls->plbuf_buffer == NULL )
00159     {
00160         // We have not allocated a buffer, so do it now
00161         if ( ( pls->plbuf_buffer = malloc( pls->plbuf_buffer_grow ) ) == NULL )
00162             plexit( "plbuf_bop: Error allocating plot buffer." );
00163 
00164         pls->plbuf_buffer_size = pls->plbuf_buffer_grow;
00165         pls->plbuf_top         = 0;
00166         pls->plbuf_readpos     = 0;
00167     }
00168     else
00169     {
00170         // Buffer is allocated, move the top to the beginning
00171         pls->plbuf_top = 0;
00172     }
00173 #endif
00174 
00175     wr_command( pls, (U_CHAR) BOP );
00176     plbuf_state( pls, PLSTATE_COLOR0 );
00177     plbuf_state( pls, PLSTATE_WIDTH );
00178 }
00179 
00180 //--------------------------------------------------------------------------
00181 // plbuf_tidy()
00182 //
00183 // Close graphics file
00184 //--------------------------------------------------------------------------
00185 
00186 void
00187 plbuf_tidy( PLStream * PL_UNUSED( pls ) )
00188 {
00189     dbug_enter( "plbuf_tidy" );
00190 
00191 #ifdef BUFFERED_FILE
00192     if ( pls->plbufFile == NULL )
00193         return;
00194 
00195     fclose( pls->plbufFile )
00196     pls->plbufFile = NULL;
00197 #endif
00198 }
00199 
00200 //--------------------------------------------------------------------------
00201 // plbuf_state()
00202 //
00203 // Handle change in PLStream state (color, pen width, fill attribute, etc).
00204 //--------------------------------------------------------------------------
00205 
00206 void
00207 plbuf_state( PLStream *pls, PLINT op )
00208 {
00209     dbug_enter( "plbuf_state" );
00210 
00211     wr_command( pls, (U_CHAR) CHANGE_STATE );
00212     wr_command( pls, (U_CHAR) op );
00213 
00214     switch ( op )
00215     {
00216     case PLSTATE_WIDTH:
00217         wr_data( pls, &( pls->width ), sizeof ( pls->width ) );
00218         break;
00219 
00220     case PLSTATE_COLOR0:
00221         wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
00222         if ( pls->icol0 == PL_RGB_COLOR )
00223         {
00224             wr_data( pls, &( pls->curcolor.r ), sizeof ( pls->curcolor.r ) );
00225             wr_data( pls, &( pls->curcolor.g ), sizeof ( pls->curcolor.g ) );
00226             wr_data( pls, &( pls->curcolor.b ), sizeof ( pls->curcolor.b ) );
00227         }
00228         break;
00229 
00230     case PLSTATE_COLOR1:
00231         wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
00232         break;
00233 
00234     case PLSTATE_FILL:
00235         wr_data( pls, &( pls->patt ), sizeof ( pls->patt ) );
00236         break;
00237     }
00238 }
00239 
00240 
00241 //--------------------------------------------------------------------------
00242 // plbuf_image()
00243 //
00244 // write image described in points pls->dev_x[], pls->dev_y[], pls->dev_z[].
00245 //                      pls->nptsX, pls->nptsY.
00246 //--------------------------------------------------------------------------
00247 
00248 static void
00249 plbuf_image( PLStream *pls, IMG_DT *img_dt )
00250 {
00251     PLINT npts = pls->dev_nptsX * pls->dev_nptsY;
00252 
00253     dbug_enter( "plbuf_image" );
00254 
00255     wr_data( pls, &pls->dev_nptsX, sizeof ( PLINT ) );
00256     wr_data( pls, &pls->dev_nptsY, sizeof ( PLINT ) );
00257 
00258     wr_data( pls, &img_dt->xmin, sizeof ( PLFLT ) );
00259     wr_data( pls, &img_dt->ymin, sizeof ( PLFLT ) );
00260     wr_data( pls, &img_dt->dx, sizeof ( PLFLT ) );
00261     wr_data( pls, &img_dt->dy, sizeof ( PLFLT ) );
00262 
00263     wr_data( pls, &pls->dev_zmin, sizeof ( short ) );
00264     wr_data( pls, &pls->dev_zmax, sizeof ( short ) );
00265 
00266     wr_data( pls, pls->dev_ix, sizeof ( short ) * (size_t) npts );
00267     wr_data( pls, pls->dev_iy, sizeof ( short ) * (size_t) npts );
00268     wr_data( pls, pls->dev_z, sizeof ( unsigned short ) * (size_t) ( ( pls->dev_nptsX - 1 ) * ( pls->dev_nptsY - 1 ) ) );
00269 }
00270 
00271 //--------------------------------------------------------------------------
00272 // plbuf_text()
00273 //
00274 // Handle text call.
00275 //--------------------------------------------------------------------------
00276 
00277 static void
00278 plbuf_text( PLStream *pls, EscText *text )
00279 {
00280     PLUNICODE fci;
00281 
00282     dbug_enter( "plbuf_text" );
00283 
00284     // Retrieve the font characterization integer
00285     plgfci( &fci );
00286 
00287     // Write the text information
00288 
00289     wr_data( pls, &fci, sizeof ( PLUNICODE ) );
00290 
00291     wr_data( pls, &pls->chrht, sizeof ( PLFLT ) );
00292     wr_data( pls, &pls->diorot, sizeof ( PLFLT ) );
00293     wr_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
00294     wr_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
00295     wr_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
00296     wr_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
00297 
00298     wr_data( pls, &text->base, sizeof ( PLINT ) );
00299     wr_data( pls, &text->just, sizeof ( PLFLT ) );
00300     wr_data( pls, text->xform, sizeof ( PLFLT ) * 4 );
00301     wr_data( pls, &text->x, sizeof ( PLINT ) );
00302     wr_data( pls, &text->y, sizeof ( PLINT ) );
00303     wr_data( pls, &text->refx, sizeof ( PLINT ) );
00304     wr_data( pls, &text->refy, sizeof ( PLINT ) );
00305 
00306     wr_data( pls, &text->unicode_array_len, sizeof ( PLINT ) );
00307     if ( text->unicode_array_len )
00308         wr_data( pls, text->unicode_array, sizeof ( PLUNICODE ) * text->unicode_array_len );
00309 }
00310 
00311 //--------------------------------------------------------------------------
00312 // plbuf_text_unicode()
00313 //
00314 // Handle text buffering for the new unicode pathway.
00315 //--------------------------------------------------------------------------
00316 
00317 static void
00318 plbuf_text_unicode( PLStream *pls, EscText *text )
00319 {
00320     PLUNICODE fci;
00321 
00322     dbug_enter( "plbuf_text" );
00323 
00324     // Retrieve the font characterization integer
00325     plgfci( &fci );
00326 
00327     // Write the text information
00328 
00329     wr_data( pls, &fci, sizeof ( PLUNICODE ) );
00330 
00331     wr_data( pls, &pls->chrht, sizeof ( PLFLT ) );
00332     wr_data( pls, &pls->diorot, sizeof ( PLFLT ) );
00333     wr_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
00334     wr_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
00335     wr_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
00336     wr_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
00337 
00338     wr_data( pls, &text->base, sizeof ( PLINT ) );
00339     wr_data( pls, &text->just, sizeof ( PLFLT ) );
00340     wr_data( pls, text->xform, sizeof ( PLFLT ) * 4 );
00341     wr_data( pls, &text->x, sizeof ( PLINT ) );
00342     wr_data( pls, &text->y, sizeof ( PLINT ) );
00343     wr_data( pls, &text->refx, sizeof ( PLINT ) );
00344     wr_data( pls, &text->refy, sizeof ( PLINT ) );
00345 
00346     wr_data( pls, &text->n_fci, sizeof ( PLUNICODE ) );
00347     wr_data( pls, &text->n_char, sizeof ( PLUNICODE ) );
00348     wr_data( pls, &text->n_ctrl_char, sizeof ( PLINT ) );
00349 
00350     wr_data( pls, &text->unicode_array_len, sizeof ( PLINT ) );
00351 }
00352 
00353 
00354 //--------------------------------------------------------------------------
00355 // plbuf_esc()
00356 //
00357 // Escape function.  Note that any data written must be in device
00358 // independent form to maintain the transportability of the metafile.
00359 //
00360 // Functions:
00361 //
00362 //      PLESC_FILL          Fill polygon
00363 //      PLESC_SWIN          Set plot window parameters
00364 //  PLESC_IMAGE     Draw image
00365 //  PLESC_HAS_TEXT  Draw PostScript text
00366 //      PLESC_CLEAR         Clear Background
00367 //      PLESC_START_RASTERIZE
00368 //      PLESC_END_RASTERIZE Start and stop rasterization
00369 //--------------------------------------------------------------------------
00370 
00371 void
00372 plbuf_esc( PLStream *pls, PLINT op, void *ptr )
00373 {
00374     dbug_enter( "plbuf_esc" );
00375 
00376     wr_command( pls, (U_CHAR) ESCAPE );
00377     wr_command( pls, (U_CHAR) op );
00378 
00379     switch ( op )
00380     {
00381     case PLESC_FILL:
00382         plbuf_fill( pls );
00383         break;
00384     case PLESC_SWIN:
00385         plbuf_swin( pls, (PLWindow *) ptr );
00386         break;
00387     case PLESC_IMAGE:
00388         plbuf_image( pls, (IMG_DT *) ptr );
00389         break;
00390     case PLESC_HAS_TEXT:
00391         if ( ptr != NULL ) // Check required by GCW driver, please don't remove
00392             plbuf_text( pls, (EscText *) ptr );
00393         break;
00394     case PLESC_BEGIN_TEXT:
00395     case PLESC_TEXT_CHAR:
00396     case PLESC_CONTROL_CHAR:
00397     case PLESC_END_TEXT:
00398         plbuf_text_unicode( pls, (EscText *) ptr );
00399         break;
00400 #if 0
00401     // These are a no-op.  They just need an entry in the buffer.
00402     case PLESC_CLEAR:
00403     case PLESC_START_RASTERIZE:
00404     case PLESC_END_RASTERIZE:
00405         break;
00406 #endif
00407     }
00408 }
00409 
00410 //--------------------------------------------------------------------------
00411 // plbuf_fill()
00412 //
00413 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
00414 //--------------------------------------------------------------------------
00415 
00416 static void
00417 plbuf_fill( PLStream *pls )
00418 {
00419     dbug_enter( "plbuf_fill" );
00420 
00421     wr_data( pls, &pls->dev_npts, sizeof ( PLINT ) );
00422     wr_data( pls, pls->dev_x, sizeof ( short ) * (size_t) pls->dev_npts );
00423     wr_data( pls, pls->dev_y, sizeof ( short ) * (size_t) pls->dev_npts );
00424 }
00425 
00426 //--------------------------------------------------------------------------
00427 // plbuf_swin()
00428 //
00429 // Set up plot window parameters.
00430 //--------------------------------------------------------------------------
00431 
00432 static void
00433 plbuf_swin( PLStream *pls, PLWindow *plwin )
00434 {
00435     wr_data( pls, &plwin->dxmi, sizeof ( PLFLT ) );
00436     wr_data( pls, &plwin->dxma, sizeof ( PLFLT ) );
00437     wr_data( pls, &plwin->dymi, sizeof ( PLFLT ) );
00438     wr_data( pls, &plwin->dyma, sizeof ( PLFLT ) );
00439 
00440     wr_data( pls, &plwin->wxmi, sizeof ( PLFLT ) );
00441     wr_data( pls, &plwin->wxma, sizeof ( PLFLT ) );
00442     wr_data( pls, &plwin->wymi, sizeof ( PLFLT ) );
00443     wr_data( pls, &plwin->wyma, sizeof ( PLFLT ) );
00444 }
00445 
00446 //--------------------------------------------------------------------------
00447 // Routines to read from & process the plot buffer.
00448 //--------------------------------------------------------------------------
00449 
00450 //--------------------------------------------------------------------------
00451 // rdbuf_init()
00452 //
00453 // Initialize device.
00454 //--------------------------------------------------------------------------
00455 
00456 static void
00457 rdbuf_init( PLStream * PL_UNUSED( pls ) )
00458 {
00459     dbug_enter( "rdbuf_init" );
00460 }
00461 
00462 //--------------------------------------------------------------------------
00463 // rdbuf_line()
00464 //
00465 // Draw a line in the current color from (x1,y1) to (x2,y2).
00466 //--------------------------------------------------------------------------
00467 
00468 static void
00469 rdbuf_line( PLStream *pls )
00470 {
00471     short xpl[2], ypl[2];
00472     PLINT npts = 2;
00473 
00474     dbug_enter( "rdbuf_line" );
00475 
00476     rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
00477     rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
00478 
00479     plP_line( xpl, ypl );
00480 }
00481 
00482 //--------------------------------------------------------------------------
00483 // rdbuf_polyline()
00484 //
00485 // Draw a polyline in the current color.
00486 //--------------------------------------------------------------------------
00487 
00488 static void
00489 rdbuf_polyline( PLStream *pls )
00490 {
00491     short _xpl[PL_MAXPOLY], _ypl[PL_MAXPOLY];
00492     short *xpl, *ypl;
00493     PLINT npts;
00494 
00495     dbug_enter( "rdbuf_polyline" );
00496 
00497     rd_data( pls, &npts, sizeof ( PLINT ) );
00498 
00499     if ( npts > PL_MAXPOLY )
00500     {
00501         xpl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
00502         ypl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
00503 
00504         if ( ( xpl == NULL ) || ( ypl == NULL ) )
00505         {
00506             plexit( "rdbuf_polyline: Insufficient memory for large polyline" );
00507         }
00508     }
00509     else
00510     {
00511         xpl = _xpl;
00512         ypl = _ypl;
00513     }
00514 
00515 
00516     rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
00517     rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
00518 
00519     plP_polyline( xpl, ypl, npts );
00520 
00521     if ( npts > PL_MAXPOLY )
00522     {
00523         free( xpl );
00524         free( ypl );
00525     }
00526 }
00527 
00528 //--------------------------------------------------------------------------
00529 // rdbuf_eop()
00530 //
00531 // End of page.
00532 //--------------------------------------------------------------------------
00533 
00534 static void
00535 rdbuf_eop( PLStream * PL_UNUSED( pls ) )
00536 {
00537     dbug_enter( "rdbuf_eop" );
00538 }
00539 
00540 //--------------------------------------------------------------------------
00541 // rdbuf_bop()
00542 //
00543 // Set up for the next page.
00544 //--------------------------------------------------------------------------
00545 
00546 static void
00547 rdbuf_bop( PLStream *pls )
00548 {
00549     dbug_enter( "rdbuf_bop" );
00550 
00551     pls->nplwin = 0;
00552 }
00553 
00554 //--------------------------------------------------------------------------
00555 // rdbuf_state()
00556 //
00557 // Handle change in PLStream state (color, pen width, fill attribute, etc).
00558 //--------------------------------------------------------------------------
00559 
00560 static void
00561 rdbuf_state( PLStream *pls )
00562 {
00563     U_CHAR op;
00564 
00565     dbug_enter( "rdbuf_state" );
00566 
00567     rd_data( pls, &op, sizeof ( U_CHAR ) );
00568 
00569     switch ( op )
00570     {
00571     case PLSTATE_WIDTH: {
00572         U_CHAR width;
00573 
00574         rd_data( pls, &width, sizeof ( U_CHAR ) );
00575         pls->width = width;
00576         plP_state( PLSTATE_WIDTH );
00577 
00578         break;
00579     }
00580 
00581     case PLSTATE_COLOR0: {
00582         short  icol0;
00583         U_CHAR r, g, b;
00584         PLFLT  a;
00585 
00586         rd_data( pls, &icol0, sizeof ( short ) );
00587         if ( icol0 == PL_RGB_COLOR )
00588         {
00589             rd_data( pls, &r, sizeof ( U_CHAR ) );
00590             rd_data( pls, &g, sizeof ( U_CHAR ) );
00591             rd_data( pls, &b, sizeof ( U_CHAR ) );
00592             a = 1.0;
00593         }
00594         else
00595         {
00596             if ( (int) icol0 >= pls->ncol0 )
00597             {
00598                 char buffer[256];
00599                 snprintf( buffer, 256, "rdbuf_state: Invalid color map entry: %d", (int) icol0 );
00600                 plabort( buffer );
00601                 return;
00602             }
00603             r = pls->cmap0[icol0].r;
00604             g = pls->cmap0[icol0].g;
00605             b = pls->cmap0[icol0].b;
00606             a = pls->cmap0[icol0].a;
00607         }
00608         pls->icol0      = icol0;
00609         pls->curcolor.r = r;
00610         pls->curcolor.g = g;
00611         pls->curcolor.b = b;
00612         pls->curcolor.a = a;
00613 
00614         plP_state( PLSTATE_COLOR0 );
00615         break;
00616     }
00617 
00618     case PLSTATE_COLOR1: {
00619         short icol1;
00620 
00621         rd_data( pls, &icol1, sizeof ( short ) );
00622 
00623         pls->icol1      = icol1;
00624         pls->curcolor.r = pls->cmap1[icol1].r;
00625         pls->curcolor.g = pls->cmap1[icol1].g;
00626         pls->curcolor.b = pls->cmap1[icol1].b;
00627         pls->curcolor.a = pls->cmap1[icol1].a;
00628 
00629         plP_state( PLSTATE_COLOR1 );
00630         break;
00631     }
00632 
00633     case PLSTATE_FILL: {
00634         signed char patt;
00635 
00636         rd_data( pls, &patt, sizeof ( signed char ) );
00637 
00638         pls->patt = patt;
00639         plP_state( PLSTATE_FILL );
00640         break;
00641     }
00642     }
00643 }
00644 
00645 //--------------------------------------------------------------------------
00646 // rdbuf_esc()
00647 //
00648 // Escape function.
00649 // Must fill data structure with whatever data that was written,
00650 // then call escape function.
00651 //
00652 // Note: it is best to only call the escape function for op-codes that
00653 // are known to be supported.
00654 //
00655 // Functions:
00656 //
00657 //      PLESC_FILL          Fill polygon
00658 //      PLESC_SWIN          Set plot window parameters
00659 //      PLESC_IMAGE         Draw image
00660 //      PLESC_HAS_TEXT      Draw PostScript text
00661 //      PLESC_BEGIN_TEXT    Commands for the alternative unicode text handling path
00662 //      PLESC_TEXT_CHAR
00663 //      PLESC_CONTROL_CHAR
00664 //      PLESC_END_TEXT
00665 //      PLESC_CLEAR         Clear Background
00666 //--------------------------------------------------------------------------
00667 
00668 static void
00669 rdbuf_image( PLStream *pls );
00670 
00671 static void
00672 rdbuf_text( PLStream *pls );
00673 
00674 static void
00675 rdbuf_text_unicode( PLINT op, PLStream *pls );
00676 
00677 static void
00678 rdbuf_esc( PLStream *pls )
00679 {
00680     U_CHAR op;
00681 
00682     dbug_enter( "rdbuf_esc" );
00683 
00684     rd_data( pls, &op, sizeof ( U_CHAR ) );
00685 
00686     switch ( op )
00687     {
00688     case PLESC_FILL:
00689         rdbuf_fill( pls );
00690         break;
00691     case PLESC_SWIN:
00692         rdbuf_swin( pls );
00693         break;
00694     case PLESC_IMAGE:
00695         rdbuf_image( pls );
00696         break;
00697     case PLESC_HAS_TEXT:
00698         rdbuf_text( pls );
00699         break;
00700     case PLESC_BEGIN_TEXT:
00701     case PLESC_TEXT_CHAR:
00702     case PLESC_CONTROL_CHAR:
00703     case PLESC_END_TEXT:
00704         rdbuf_text_unicode( op, pls );
00705         break;
00706     case PLESC_CLEAR:
00707         plP_esc( PLESC_CLEAR, NULL );
00708         break;
00709     case PLESC_START_RASTERIZE:
00710         plP_esc( PLESC_START_RASTERIZE, NULL );
00711         break;
00712     case PLESC_END_RASTERIZE:
00713         plP_esc( PLESC_END_RASTERIZE, NULL );
00714         break;
00715     }
00716 }
00717 
00718 //--------------------------------------------------------------------------
00719 // rdbuf_fill()
00720 //
00721 // Fill polygon described by input points.
00722 //--------------------------------------------------------------------------
00723 
00724 static void
00725 rdbuf_fill( PLStream *pls )
00726 {
00727     short _xpl[PL_MAXPOLY], _ypl[PL_MAXPOLY];
00728     short *xpl, *ypl;
00729     PLINT npts;
00730 
00731     dbug_enter( "rdbuf_fill" );
00732 
00733     rd_data( pls, &npts, sizeof ( PLINT ) );
00734 
00735     if ( npts > PL_MAXPOLY )
00736     {
00737         xpl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
00738         ypl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
00739 
00740         if ( ( xpl == NULL ) || ( ypl == NULL ) )
00741         {
00742             plexit( "rdbuf_polyline: Insufficient memory for large polyline" );
00743         }
00744     }
00745     else
00746     {
00747         xpl = _xpl;
00748         ypl = _ypl;
00749     }
00750 
00751     rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
00752     rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
00753 
00754     plP_fill( xpl, ypl, npts );
00755 
00756     if ( npts > PL_MAXPOLY )
00757     {
00758         free( xpl );
00759         free( ypl );
00760     }
00761 }
00762 
00763 //--------------------------------------------------------------------------
00764 // rdbuf_image()
00765 //
00766 // .
00767 //--------------------------------------------------------------------------
00768 
00769 static void
00770 rdbuf_image( PLStream *pls )
00771 {
00772     // Unnecessarily initialize dev_iy and dev_z to quiet -O1
00773     // -Wuninitialized warnings which are false alarms.  (If something
00774     // goes wrong with the dev_ix malloc below any further use of
00775     // dev_iy and dev_z does not occur.  Similarly, if something goes
00776     // wrong with the dev_iy malloc below any further use of dev_z
00777     // does not occur.)
00778     short          *dev_ix, *dev_iy = NULL;
00779     unsigned short *dev_z = NULL, dev_zmin, dev_zmax;
00780     PLINT          nptsX, nptsY, npts;
00781     PLFLT          xmin, ymin, dx, dy;
00782 
00783     dbug_enter( "rdbuf_image" );
00784 
00785     rd_data( pls, &nptsX, sizeof ( PLINT ) );
00786     rd_data( pls, &nptsY, sizeof ( PLINT ) );
00787     npts = nptsX * nptsY;
00788 
00789     rd_data( pls, &xmin, sizeof ( PLFLT ) );
00790     rd_data( pls, &ymin, sizeof ( PLFLT ) );
00791     rd_data( pls, &dx, sizeof ( PLFLT ) );
00792     rd_data( pls, &dy, sizeof ( PLFLT ) );
00793 
00794     rd_data( pls, &dev_zmin, sizeof ( short ) );
00795     rd_data( pls, &dev_zmax, sizeof ( short ) );
00796 
00797     // NOTE:  Even though for memory buffered version all the data is in memory,
00798     // we still allocate and copy the data because I think that method works
00799     // better in a multithreaded environment.  I could be wrong.
00800     //
00801     if ( ( ( dev_ix = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
00802          ( ( dev_iy = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
00803          ( ( dev_z = (unsigned short *) malloc( (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) * sizeof ( unsigned short ) ) ) == NULL ) )
00804         plexit( "rdbuf_image: Insufficient memory" );
00805 
00806     rd_data( pls, dev_ix, sizeof ( short ) * (size_t) npts );
00807     rd_data( pls, dev_iy, sizeof ( short ) * (size_t) npts );
00808     rd_data( pls, dev_z, sizeof ( unsigned short ) * (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) );
00809 
00810     //
00811     // COMMENTED OUT by Hezekiah Carty
00812     // Commented (hopefullly temporarily) until the dev_fastimg rendering
00813     // path can be updated to support the new plimage internals. In the
00814     // meantime this function is not actually used so the issue of how to
00815     // update the code to support the new interface can be ignored.
00816     //
00817     //plP_image(dev_ix, dev_iy, dev_z, nptsX, nptsY, xmin, ymin, dx, dy, dev_zmin, dev_zmax);
00818 
00819     free( dev_ix );
00820     free( dev_iy );
00821     free( dev_z );
00822 }
00823 
00824 //--------------------------------------------------------------------------
00825 // rdbuf_swin()
00826 //
00827 // Set up plot window parameters.
00828 //--------------------------------------------------------------------------
00829 
00830 static void
00831 rdbuf_swin( PLStream *pls )
00832 {
00833     PLWindow plwin;
00834 
00835     rd_data( pls, &plwin.dxmi, sizeof ( PLFLT ) );
00836     rd_data( pls, &plwin.dxma, sizeof ( PLFLT ) );
00837     rd_data( pls, &plwin.dymi, sizeof ( PLFLT ) );
00838     rd_data( pls, &plwin.dyma, sizeof ( PLFLT ) );
00839 
00840     rd_data( pls, &plwin.wxmi, sizeof ( PLFLT ) );
00841     rd_data( pls, &plwin.wxma, sizeof ( PLFLT ) );
00842     rd_data( pls, &plwin.wymi, sizeof ( PLFLT ) );
00843     rd_data( pls, &plwin.wyma, sizeof ( PLFLT ) );
00844 
00845     plP_swin( &plwin );
00846 }
00847 
00848 //--------------------------------------------------------------------------
00849 // rdbuf_text()
00850 //
00851 // Draw PostScript text.
00852 //--------------------------------------------------------------------------
00853 
00854 static void
00855 rdbuf_text( PLStream *pls )
00856 {
00857     PLUNICODE( fci );
00858     EscText  text;
00859     PLFLT    xform[4];
00860     PLUNICODE* unicode;
00861 
00862     text.xform = xform;
00863 
00864 
00865     // Read in the data
00866 
00867     rd_data( pls, &fci, sizeof ( PLUNICODE ) );
00868 
00869     rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
00870     rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
00871     rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
00872     rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
00873     rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
00874     rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
00875 
00876     rd_data( pls, &text.base, sizeof ( PLINT ) );
00877     rd_data( pls, &text.just, sizeof ( PLFLT ) );
00878     rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
00879     rd_data( pls, &text.x, sizeof ( PLINT ) );
00880     rd_data( pls, &text.y, sizeof ( PLINT ) );
00881     rd_data( pls, &text.refx, sizeof ( PLINT ) );
00882     rd_data( pls, &text.refy, sizeof ( PLINT ) );
00883 
00884     rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
00885     if ( text.unicode_array_len )
00886     {
00887         if ( ( unicode = (PLUNICODE *) malloc( text.unicode_array_len * sizeof ( PLUNICODE ) ) )
00888              == NULL )
00889             plexit( "rdbuf_text: Insufficient memory" );
00890 
00891         rd_data( pls, unicode, sizeof ( PLUNICODE ) * text.unicode_array_len );
00892         text.unicode_array = unicode;
00893     }
00894     else
00895         text.unicode_array = NULL;
00896 
00897     // Make the call for unicode devices
00898     if ( pls->dev_unicode )
00899     {
00900         plsfci( fci );
00901         plP_esc( PLESC_HAS_TEXT, &text );
00902     }
00903 }
00904 
00905 //--------------------------------------------------------------------------
00906 // rdbuf_text_unicode()
00907 //
00908 // Draw text for the new unicode handling pathway.
00909 //--------------------------------------------------------------------------
00910 
00911 static void
00912 rdbuf_text_unicode( PLINT op, PLStream *pls )
00913 {
00914     PLUNICODE( fci );
00915     EscText text;
00916     PLFLT   xform[4];
00917 
00918     text.xform = xform;
00919 
00920 
00921     // Read in the data
00922 
00923     rd_data( pls, &fci, sizeof ( PLUNICODE ) );
00924 
00925     rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
00926     rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
00927     rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
00928     rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
00929     rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
00930     rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
00931 
00932     rd_data( pls, &text.base, sizeof ( PLINT ) );
00933     rd_data( pls, &text.just, sizeof ( PLFLT ) );
00934     rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
00935     rd_data( pls, &text.x, sizeof ( PLINT ) );
00936     rd_data( pls, &text.y, sizeof ( PLINT ) );
00937     rd_data( pls, &text.refx, sizeof ( PLINT ) );
00938     rd_data( pls, &text.refy, sizeof ( PLINT ) );
00939 
00940     rd_data( pls, &text.n_fci, sizeof ( PLUNICODE ) );
00941     rd_data( pls, &text.n_char, sizeof ( PLUNICODE ) );
00942     rd_data( pls, &text.n_ctrl_char, sizeof ( PLINT ) );
00943 
00944     rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
00945 
00946     if ( pls->dev_unicode )
00947     {
00948         plsfci( fci );
00949         plP_esc( op, &text );
00950     }
00951 }
00952 
00953 //--------------------------------------------------------------------------
00954 // plRemakePlot()
00955 //
00956 // Rebuilds plot from plot buffer, usually in response to a window
00957 // resize or exposure event.
00958 //--------------------------------------------------------------------------
00959 
00960 void
00961 plRemakePlot( PLStream *pls )
00962 {
00963     U_CHAR   c;
00964     int      plbuf_status;
00965     PLStream *save_pls;
00966 
00967     dbug_enter( "plRemakePlot" );
00968 
00969     // Change the status of the flags before checking for a buffer.
00970     // Actually, more thought is needed if we want to support multithreaded
00971     // code correctly, specifically the case where two threads are using
00972     // the same plot stream (e.g. one thread is drawing the plot and another
00973     // thread is processing window manager messages).
00974     //
00975     plbuf_status     = pls->plbuf_write;
00976     pls->plbuf_write = FALSE;
00977     pls->plbuf_read  = TRUE;
00978 
00979 #ifdef BUFFERED_FILE
00980     if ( pls->plbufFile )
00981     {
00982         rewind( pls->plbufFile );
00983 #else
00984     if ( pls->plbuf_buffer )
00985     {
00986         pls->plbuf_readpos = 0;
00987 #endif
00988         // Need to change where plsc points to before processing the commands.
00989         // If we have multiple plot streams, this will prevent the commands from
00990         // going to the wrong plot stream.
00991         //
00992         save_pls = plsc;
00993         plsc     = pls;
00994 
00995         while ( rd_command( pls, &c ) )
00996         {
00997             plbuf_control( pls, c );
00998         }
00999 
01000         plsc = save_pls;
01001     }
01002 
01003     pls->plbuf_read  = FALSE;
01004     pls->plbuf_write = plbuf_status;
01005 }
01006 
01007 //--------------------------------------------------------------------------
01008 // plbuf_control()
01009 //
01010 // Processes commands read from the plot buffer.
01011 //--------------------------------------------------------------------------
01012 
01013 static void
01014 plbuf_control( PLStream *pls, U_CHAR c )
01015 {
01016     static U_CHAR c_old = 0;
01017 
01018     dbug_enter( "plbuf_control" );
01019 
01020     switch ( (int) c )
01021     {
01022     case INITIALIZE:
01023         rdbuf_init( pls );
01024         break;
01025 
01026     case EOP:
01027         rdbuf_eop( pls );
01028         break;
01029 
01030     case BOP:
01031         rdbuf_bop( pls );
01032         break;
01033 
01034     case CHANGE_STATE:
01035         rdbuf_state( pls );
01036         break;
01037 
01038     case LINE:
01039         rdbuf_line( pls );
01040         break;
01041 
01042     case POLYLINE:
01043         rdbuf_polyline( pls );
01044         break;
01045 
01046     case ESCAPE:
01047         rdbuf_esc( pls );
01048         break;
01049 
01050     default:
01051         pldebug( "plbuf_control", "Unrecognized command %d, previous %d\n", c, c_old );
01052     }
01053     c_old = c;
01054 }
01055 
01056 //--------------------------------------------------------------------------
01057 // rd_command()
01058 //
01059 // Read & return the next command
01060 //--------------------------------------------------------------------------
01061 
01062 static int
01063 rd_command( PLStream *pls, U_CHAR *p_c )
01064 {
01065     int count;
01066 
01067 #ifdef BUFFERED_FILE
01068     count = fread( p_c, sizeof ( U_CHAR ), 1, pls->plbufFile );
01069 #else
01070     if ( pls->plbuf_readpos < pls->plbuf_top )
01071     {
01072         *p_c = *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos );
01073         pls->plbuf_readpos += sizeof ( U_CHAR );
01074         count = sizeof ( U_CHAR );
01075     }
01076     else
01077     {
01078         count = 0;
01079     }
01080 #endif
01081     return ( count );
01082 }
01083 
01084 //--------------------------------------------------------------------------
01085 // rd_data()
01086 //
01087 // Read the data associated with the command
01088 //--------------------------------------------------------------------------
01089 
01090 static void
01091 rd_data( PLStream *pls, void *buf, size_t buf_size )
01092 {
01093 #ifdef BUFFERED_FILE
01094     plio_fread( buf, buf_size, 1, pls->plbufFile );
01095 #else
01096 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
01097 // then this code will have problems.  A better approach might be to use
01098 // uint8_t from <stdint.h> but I do not know how portable that approach is
01099 //
01100     memcpy( buf, (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos, buf_size );
01101     pls->plbuf_readpos += buf_size;
01102 #endif
01103 }
01104 
01105 //--------------------------------------------------------------------------
01106 // wr_command()
01107 //
01108 // Write the next command
01109 //--------------------------------------------------------------------------
01110 
01111 static void
01112 wr_command( PLStream *pls, U_CHAR c )
01113 {
01114 #ifdef BUFFERED_FILE
01115     plio_fwrite( &c1, sizeof ( U_CHAR ), 1, pls->plbufFile );
01116 #else
01117     if ( ( pls->plbuf_top + sizeof ( U_CHAR ) ) >= pls->plbuf_buffer_size )
01118     {
01119         // Not enough space, need to grow the buffer
01120         pls->plbuf_buffer_size += pls->plbuf_buffer_grow;
01121 
01122         if ( pls->verbose )
01123             printf( "Growing buffer to %d KB\n", (int) ( pls->plbuf_buffer_size / 1024 ) );
01124         if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
01125             plexit( "plbuf wr_data:  Plot buffer grow failed" );
01126     }
01127 
01128     *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top ) = c;
01129     pls->plbuf_top += sizeof ( U_CHAR );
01130 #endif
01131 }
01132 
01133 //--------------------------------------------------------------------------
01134 // wr_data()
01135 //
01136 // Write the data associated with a command
01137 //--------------------------------------------------------------------------
01138 
01139 static void
01140 wr_data( PLStream *pls, void *buf, size_t buf_size )
01141 {
01142 #ifdef BUFFERED_FILE
01143     plio_fwrite( buf, buf_size, 1, pls->plbufFile );
01144 #else
01145     if ( ( pls->plbuf_top + buf_size ) >= pls->plbuf_buffer_size )
01146     {
01147         // Not enough space, need to grow the buffer
01148         // Must make sure the increase is enough for this data
01149         pls->plbuf_buffer_size += pls->plbuf_buffer_grow *
01150                                   ( ( pls->plbuf_top + buf_size - pls->plbuf_buffer_size ) /
01151                                     pls->plbuf_buffer_grow + 1 );
01152         while ( pls->plbuf_top + buf_size >= pls->plbuf_buffer_size )
01153             ;
01154 
01155         if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
01156             plexit( "plbuf wr_data:  Plot buffer grow failed" );
01157     }
01158 
01159 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
01160 // then this code will have problems.  A better approach might be to use
01161 // uint8_t from <stdint.h> but I do not know how portable that approach is
01162 //
01163     memcpy( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top, buf, buf_size );
01164     pls->plbuf_top += buf_size;
01165 #endif
01166 }
01167 
01168 // plbuf_save(state)
01169 //
01170 // Saves the current state of the plot into a save buffer.
01171 // This code was originally in gcw.c and gcw-lib.c.  The original
01172 // code used a temporary file for the plot buffer and memory
01173 // to perserve colormaps.  That method does not offer a clean
01174 // break between using memory buffers and file buffers.  This
01175 // function preserves the same functionality by returning a data
01176 // structure that saves the plot buffer and colormaps seperately.
01177 //
01178 // The caller passes an existing save buffer for reuse or NULL
01179 // to force the allocation of a new buffer.  Since one malloc()
01180 // is used for everything, the entire save buffer can be freed
01181 // with one free() call.
01182 //
01183 //
01184 struct _color_map
01185 {
01186     PLColor *cmap;
01187     PLINT   icol;
01188     PLINT   ncol;
01189 };
01190 
01191 struct _state
01192 {
01193     size_t            size;  // Size of the save buffer
01194     int               valid; // Flag to indicate a valid save state
01195 #ifdef BUFFERED_FILE
01196     FILE              *plbufFile;
01197 #else
01198     void              *plbuf_buffer;
01199     size_t            plbuf_buffer_size;
01200     size_t            plbuf_top;
01201     size_t            plbuf_readpos;
01202 #endif
01203     struct _color_map *color_map;
01204 };
01205 
01206 void * plbuf_save( PLStream *pls, void *state )
01207 {
01208     size_t        save_size;
01209     struct _state *plot_state = (struct _state *) state;
01210     PLINT         i;
01211     U_CHAR        *buf; // Assume that this is byte-sized
01212 
01213     if ( pls->plbuf_write )
01214     {
01215         pls->plbuf_write = FALSE;
01216         pls->plbuf_read  = TRUE;
01217 
01218         // Determine the size of the buffer required to save everything. We
01219         // assume that there are only two colormaps, but have written the code
01220         // that more than two can be handled with minimal changes.
01221         //
01222         save_size = sizeof ( struct _state )
01223                     + 2 * sizeof ( struct _color_map )
01224                     + (size_t) ( pls->ncol0 ) * sizeof ( PLColor )
01225                     + (size_t) ( pls->ncol1 ) * sizeof ( PLColor );
01226 
01227 #ifndef BUFFERED_FILE
01228         // Only copy as much of the plot buffer that is being used
01229         save_size += pls->plbuf_top;
01230 #endif
01231 
01232         // If a buffer exists, determine if we need to resize it
01233         if ( state != NULL )
01234         {
01235             // We have a save buffer, is it smaller than the current size requirement?
01236             if ( plot_state->size < save_size )
01237             {
01238                 // Yes, reallocate a larger one
01239                 if ( ( plot_state = (struct _state *) realloc( state, save_size ) ) == NULL )
01240                 {
01241                     // NOTE: If realloc fails, then plot_state ill be NULL.
01242                     // This will leave the original buffer untouched, thus we
01243                     // mark it as invalid and return it back to the caller.
01244                     //
01245                     plwarn( "plbuf: Unable to reallocate sufficient memory to save state" );
01246                     plot_state->valid = 0;
01247 
01248                     return state;
01249                 }
01250                 plot_state->size = save_size;
01251             }
01252         }
01253         else
01254         {
01255             // A buffer does not exist, so we need to allocate one
01256             if ( ( plot_state = (struct _state *) malloc( save_size ) ) == NULL )
01257             {
01258                 plwarn( "plbuf: Unable to allocate sufficient memory to save state" );
01259 
01260                 return NULL;
01261             }
01262             plot_state->size = save_size;
01263 
01264 #ifdef BUFFERED_FILE
01265             // Make sure the FILE pointer is NULL in order to preven bad things from happening...
01266             plot_state->plbufFile = NULL;
01267 #endif
01268         }
01269 
01270         // At this point we have an appropriately sized save buffer.
01271         // We need to invalidate the state of the save buffer, since it
01272         // will not be valid until after everything is copied.  We use
01273         // this approach vice freeing the memory and returning a NULL pointer
01274         // in order to prevent allocating and freeing memory needlessly.
01275         //
01276         plot_state->valid = 0;
01277 
01278         // Point buf to the space after the struct _state
01279         buf = (U_CHAR *) ( plot_state + 1 );
01280 
01281 #ifdef BUFFERED_FILE
01282         // Remove the old tempfile, if it exists
01283         if ( plot_state->plbufFile != NULL )
01284         {
01285             fclose( plot_state->plbufFile );
01286         }
01287 
01288         // Copy the plot buffer to a tempfile
01289         if ( ( plot_state->plbufFile = pl_create_tempfile( NULL ) ) == NULL )
01290         {
01291             // Throw a warning since this might be a permissions problem
01292             // and we may not want to force an exit
01293             //
01294             plwarn( "plbuf: Unable to open temporary file to save state" );
01295             return (void *) plot_state;
01296         }
01297         else
01298         {
01299             U_CHAR tmp;
01300 
01301             rewind( pls->plbufFile );
01302             while ( count = fread( &tmp, sizeof ( U_CHAR ), 1, pls->plbufFile ) )
01303             {
01304                 if ( fwrite( &tmp, sizeof ( U_CHAR ), 1, plot_state->plbufFile ) != count )
01305                 {
01306                     // Throw a warning since this might be a permissions problem
01307                     // and we may not want to force an exit
01308                     //
01309                     plwarn( "plbuf: Unable to write to temporary file" );
01310                     fclose( plot_state->plbufFile );
01311                     plot_state->plbufFile = NULL;
01312                     return (void *) plot_state;
01313                 }
01314             }
01315         }
01316 #else
01317         // Again, note, that we only copy the portion of the plot buffer that is being used
01318         plot_state->plbuf_buffer_size = pls->plbuf_top;
01319         plot_state->plbuf_top         = pls->plbuf_top;
01320         plot_state->plbuf_readpos     = 0;
01321 
01322         // Create a pointer that points in the space we allocated after struct _state
01323         plot_state->plbuf_buffer = (void *) buf;
01324         buf += pls->plbuf_top;
01325 
01326         // Copy the plot buffer to our new buffer.  Again, I must stress, that we only
01327         // are copying the portion of the plot buffer that is being used
01328         //
01329         if ( memcpy( plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL )
01330         {
01331             // This should never be NULL
01332             plwarn( "plbuf: Got a NULL in memcpy!" );
01333             return (void *) plot_state;
01334         }
01335 #endif
01336 
01337         pls->plbuf_write = TRUE;
01338         pls->plbuf_read  = FALSE;
01339 
01340         // Save the colormaps.  First create a pointer that points in the space we allocated
01341         // after the plot buffer
01342         plot_state->color_map = (struct _color_map *) buf;
01343         buf += sizeof ( struct _color_map ) * 2;
01344 
01345         // Then we need to make space for the colormaps themselves
01346         plot_state->color_map[0].cmap = (PLColor *) buf;
01347         buf += sizeof ( PLColor ) * (size_t) ( pls->ncol0 );
01348         plot_state->color_map[1].cmap = (PLColor *) buf;
01349         buf += sizeof ( PLColor ) * (size_t) ( pls->ncol1 );
01350 
01351         // Save cmap 0
01352         plot_state->color_map[0].icol = pls->icol0;
01353         plot_state->color_map[0].ncol = pls->ncol0;
01354         for ( i = 0; i < pls->ncol0; i++ )
01355         {
01356             pl_cpcolor( &( plot_state->color_map[0].cmap[i] ), &pls->cmap0[i] );
01357         }
01358 
01359         // Save cmap 1
01360         plot_state->color_map[1].icol = pls->icol1;
01361         plot_state->color_map[1].ncol = pls->ncol1;
01362         for ( i = 0; i < pls->ncol1; i++ )
01363         {
01364             pl_cpcolor( &( plot_state->color_map[1].cmap[i] ), &pls->cmap1[i] );
01365         }
01366 
01367         plot_state->valid = 1;
01368         return (void *) plot_state;
01369     }
01370 
01371     return NULL;
01372 }
01373 
01374 // plbuf_restore(PLStream *, state)
01375 //
01376 // Restores the passed state
01377 //
01378 void plbuf_restore( PLStream *pls, void *state )
01379 {
01380     struct _state *new_state = (struct _state *) state;
01381 
01382 #ifdef BUFFERED_FILE
01383     pls->plbufFile = new_state->save_file;
01384 #else
01385     pls->plbuf_buffer      = new_state->plbuf_buffer;
01386     pls->plbuf_buffer_size = new_state->plbuf_buffer_size;
01387     pls->plbuf_top         = new_state->plbuf_top;
01388     pls->plbuf_readpos     = new_state->plbuf_readpos;
01389 #endif
01390     // cmap 0
01391     pls->cmap0 = new_state->color_map[0].cmap;
01392     pls->icol0 = new_state->color_map[0].icol;
01393     pls->ncol0 = new_state->color_map[0].ncol;
01394     // cmap 1
01395     pls->cmap1 = new_state->color_map[1].cmap;
01396     pls->icol1 = new_state->color_map[1].icol;
01397     pls->ncol1 = new_state->color_map[1].ncol;
01398 }
01399 
01400 // plbuf_switch(PLStream *, state)
01401 //
01402 // Makes the passed state the current one.  Preserves the previous state
01403 // by returning a save buffer.
01404 //
01405 // NOTE:  The current implementation can cause a memory leak under the
01406 // following scenario:
01407 //    1) plbuf_save() is called
01408 //    2) plbuf_switch() is called
01409 //    3) Commands are called which cause the plot buffer to grow
01410 //    4) plbuf_swtich() is called
01411 //
01412 void * plbuf_switch( PLStream *pls, void *state )
01413 {
01414     struct _state *new_state = (struct _state *) state;
01415     struct _state *prev_state;
01416     size_t        save_size;
01417 
01418     // No saved state was passed, return a NULL--we hope the caller
01419     // is smart enough to notice
01420     //
01421     if ( state == NULL )
01422         return NULL;
01423 
01424     if ( !new_state->valid )
01425     {
01426         plwarn( "plbuf: Attempting to switch to an invalid saved state" );
01427         return NULL;
01428     }
01429 
01430     save_size = sizeof ( struct _state )
01431                 + 2 * sizeof ( struct _color_map );
01432 
01433     if ( ( prev_state = (struct _state *) malloc( save_size ) ) == NULL )
01434     {
01435         plwarn( "plbuf: Unable to allocate memory to save state" );
01436         return NULL;
01437     }
01438 
01439     // Set some housekeeping variables
01440     prev_state->size  = save_size;
01441     prev_state->valid = 1;
01442 
01443     // Preserve the existing state
01444 #ifdef BUFFERED_FILE
01445     prev_state->plbufFile = pls->plbufFile;
01446 #else
01447     prev_state->plbuf_buffer      = pls->plbuf_buffer;
01448     prev_state->plbuf_buffer_size = pls->plbuf_buffer_size;
01449     prev_state->plbuf_top         = pls->plbuf_top;
01450     prev_state->plbuf_readpos     = pls->plbuf_readpos;
01451 #endif
01452     // cmap 0
01453     prev_state->color_map[0].cmap = pls->cmap0;
01454     prev_state->color_map[0].icol = pls->icol0;
01455     prev_state->color_map[0].ncol = pls->ncol0;
01456     // cmap 1
01457     prev_state->color_map[1].cmap = pls->cmap1;
01458     prev_state->color_map[1].icol = pls->icol1;
01459     prev_state->color_map[1].ncol = pls->ncol1;
01460 
01461     plbuf_restore( pls, new_state );
01462 
01463     return (void *) prev_state;
01464 }
01465 
01466 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines