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