PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plbuf.c
Go to the documentation of this file.
1 // Handle plot buffer.
2 //
3 // Copyright (C) 1992 Maurice LeBrun
4 // Copyright (C) 2004-2014 Alan W. Irwin
5 // Copyright (C) 2005 Thomas J. Duck
6 // Copyright (C) 2006 Jim Dishaw
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 
25 #define NEED_PLDEBUG
26 #include "plplotP.h"
27 #include "drivers.h"
28 #include "metadefs.h"
29 
30 #include <string.h>
31 
32 // Function prototypes
33 void * plbuf_save( PLStream *pls, void *state );
34 
35 static int rd_command( PLStream *pls, U_CHAR *p_c );
36 static void rd_data( PLStream *pls, void *buf, size_t buf_size );
37 static void wr_command( PLStream *pls, U_CHAR c );
38 static void wr_data( PLStream *pls, void *buf, size_t buf_size );
39 static void plbuf_control( PLStream *pls, U_CHAR c );
40 
41 static void rdbuf_init( PLStream *pls );
42 static void rdbuf_line( PLStream *pls );
43 static void rdbuf_polyline( PLStream *pls );
44 static void rdbuf_eop( PLStream *pls );
45 static void rdbuf_bop( PLStream *pls );
46 static void rdbuf_state( PLStream *pls );
47 static void rdbuf_esc( PLStream *pls );
48 
49 static void plbuf_fill( PLStream *pls );
50 static void rdbuf_fill( PLStream *pls );
51 static void plbuf_swin( PLStream *pls, PLWindow *plwin );
52 static void rdbuf_swin( PLStream *pls );
53 
54 //--------------------------------------------------------------------------
55 // plbuf_init()
56 //
57 // Initialize device.
58 // Actually just disables writes if plot buffer is already open (occurs
59 // when one stream is cloned, as in printing).
60 //--------------------------------------------------------------------------
61 
62 void
64 {
65  dbug_enter( "plbuf_init" );
66 
67  pls->plbuf_read = FALSE;
68 #ifdef BUFFERED_FILE
69  if ( pls->plbufFile != NULL )
70  pls->plbuf_write = FALSE;
71 #else
72  if ( pls->plbuf_buffer != NULL )
73  pls->plbuf_write = FALSE;
74 #endif
75 }
76 
77 //--------------------------------------------------------------------------
78 // plbuf_line()
79 //
80 // Draw a line in the current color from (x1,y1) to (x2,y2).
81 //--------------------------------------------------------------------------
82 
83 void
84 plbuf_line( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
85 {
86  short xpl[2], ypl[2];
87 
88  dbug_enter( "plbuf_line" );
89 
90  wr_command( pls, (U_CHAR) LINE );
91 
92  xpl[0] = x1a;
93  xpl[1] = x2a;
94  ypl[0] = y1a;
95  ypl[1] = y2a;
96 
97  wr_data( pls, xpl, sizeof ( short ) * 2 );
98  wr_data( pls, ypl, sizeof ( short ) * 2 );
99 }
100 
101 //--------------------------------------------------------------------------
102 // plbuf_polyline()
103 //
104 // Draw a polyline in the current color.
105 //--------------------------------------------------------------------------
106 
107 void
108 plbuf_polyline( PLStream *pls, short *xa, short *ya, PLINT npts )
109 {
110  dbug_enter( "plbuf_polyline" );
111 
112  wr_command( pls, (U_CHAR) POLYLINE );
113 
114  wr_data( pls, &npts, sizeof ( PLINT ) );
115 
116  wr_data( pls, xa, sizeof ( short ) * (size_t) npts );
117  wr_data( pls, ya, sizeof ( short ) * (size_t) npts );
118 }
119 
120 //--------------------------------------------------------------------------
121 // plbuf_eop()
122 //
123 // End of page.
124 //--------------------------------------------------------------------------
125 
126 void
128 {
129  dbug_enter( "plbuf_eop" );
130 }
131 
132 //--------------------------------------------------------------------------
133 // plbuf_bop()
134 //
135 // Set up for the next page.
136 // To avoid problems redisplaying partially filled pages, on each BOP the
137 // old file is thrown away and a new one is obtained. This way we can just
138 // read up to EOF to get everything on the current page.
139 //
140 // Also write state information to ensure the next page is correct.
141 //--------------------------------------------------------------------------
142 
143 void
145 {
146  dbug_enter( "plbuf_bop" );
147 
148  plbuf_tidy( pls );
149 
150 #ifdef BUFFERED_FILE
151  pls->plbufFile = pl_create_tempfile( NULL );
152  if ( pls->plbufFile == NULL )
153  plexit( "plbuf_bop: Error opening plot data storage file." );
154 #else
155  // Need a better place to initialize this value
156  pls->plbuf_buffer_grow = 128 * 1024;
157 
158  if ( pls->plbuf_buffer == NULL )
159  {
160  // We have not allocated a buffer, so do it now
161  if ( ( pls->plbuf_buffer = malloc( pls->plbuf_buffer_grow ) ) == NULL )
162  plexit( "plbuf_bop: Error allocating plot buffer." );
163 
165  pls->plbuf_top = 0;
166  pls->plbuf_readpos = 0;
167  }
168  else
169  {
170  // Buffer is allocated, move the top to the beginning
171  pls->plbuf_top = 0;
172  }
173 #endif
174 
175  wr_command( pls, (U_CHAR) BOP );
176  plbuf_state( pls, PLSTATE_COLOR0 );
177  plbuf_state( pls, PLSTATE_WIDTH );
178 }
179 
180 //--------------------------------------------------------------------------
181 // plbuf_tidy()
182 //
183 // Close graphics file
184 //--------------------------------------------------------------------------
185 
186 void
188 {
189  dbug_enter( "plbuf_tidy" );
190 
191 #ifdef BUFFERED_FILE
192  if ( pls->plbufFile == NULL )
193  return;
194 
195  fclose( pls->plbufFile )
196  pls->plbufFile = NULL;
197 #endif
198 }
199 
200 //--------------------------------------------------------------------------
201 // plbuf_state()
202 //
203 // Handle change in PLStream state (color, pen width, fill attribute, etc).
204 //--------------------------------------------------------------------------
205 
206 void
208 {
209  dbug_enter( "plbuf_state" );
210 
211  wr_command( pls, (U_CHAR) CHANGE_STATE );
212  wr_command( pls, (U_CHAR) op );
213 
214  switch ( op )
215  {
216  case PLSTATE_WIDTH:
217  wr_data( pls, &( pls->width ), sizeof ( pls->width ) );
218  break;
219 
220  case PLSTATE_COLOR0:
221  wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
222  if ( pls->icol0 == PL_RGB_COLOR )
223  {
224  wr_data( pls, &( pls->curcolor.r ), sizeof ( pls->curcolor.r ) );
225  wr_data( pls, &( pls->curcolor.g ), sizeof ( pls->curcolor.g ) );
226  wr_data( pls, &( pls->curcolor.b ), sizeof ( pls->curcolor.b ) );
227  }
228  break;
229 
230  case PLSTATE_COLOR1:
231  wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
232  break;
233 
234  case PLSTATE_FILL:
235  wr_data( pls, &( pls->patt ), sizeof ( pls->patt ) );
236  break;
237  }
238 }
239 
240 
241 //--------------------------------------------------------------------------
242 // plbuf_image()
243 //
244 // write image described in points pls->dev_x[], pls->dev_y[], pls->dev_z[].
245 // pls->nptsX, pls->nptsY.
246 //--------------------------------------------------------------------------
247 
248 static void
249 plbuf_image( PLStream *pls, IMG_DT *img_dt )
250 {
251  PLINT npts = pls->dev_nptsX * pls->dev_nptsY;
252 
253  dbug_enter( "plbuf_image" );
254 
255  wr_data( pls, &pls->dev_nptsX, sizeof ( PLINT ) );
256  wr_data( pls, &pls->dev_nptsY, sizeof ( PLINT ) );
257 
258  wr_data( pls, &img_dt->xmin, sizeof ( PLFLT ) );
259  wr_data( pls, &img_dt->ymin, sizeof ( PLFLT ) );
260  wr_data( pls, &img_dt->dx, sizeof ( PLFLT ) );
261  wr_data( pls, &img_dt->dy, sizeof ( PLFLT ) );
262 
263  wr_data( pls, &pls->dev_zmin, sizeof ( short ) );
264  wr_data( pls, &pls->dev_zmax, sizeof ( short ) );
265 
266  wr_data( pls, pls->dev_ix, sizeof ( short ) * (size_t) npts );
267  wr_data( pls, pls->dev_iy, sizeof ( short ) * (size_t) npts );
268  wr_data( pls, pls->dev_z, sizeof ( unsigned short ) * (size_t) ( ( pls->dev_nptsX - 1 ) * ( pls->dev_nptsY - 1 ) ) );
269 }
270 
271 //--------------------------------------------------------------------------
272 // plbuf_text()
273 //
274 // Handle text call.
275 //--------------------------------------------------------------------------
276 
277 static void
279 {
280  PLUNICODE fci;
281 
282  dbug_enter( "plbuf_text" );
283 
284  // Retrieve the font characterization integer
285  plgfci( &fci );
286 
287  // Write the text information
288 
289  wr_data( pls, &fci, sizeof ( PLUNICODE ) );
290 
291  wr_data( pls, &pls->chrht, sizeof ( PLFLT ) );
292  wr_data( pls, &pls->diorot, sizeof ( PLFLT ) );
293  wr_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
294  wr_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
295  wr_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
296  wr_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
297 
298  wr_data( pls, &text->base, sizeof ( PLINT ) );
299  wr_data( pls, &text->just, sizeof ( PLFLT ) );
300  wr_data( pls, text->xform, sizeof ( PLFLT ) * 4 );
301  wr_data( pls, &text->x, sizeof ( PLINT ) );
302  wr_data( pls, &text->y, sizeof ( PLINT ) );
303  wr_data( pls, &text->refx, sizeof ( PLINT ) );
304  wr_data( pls, &text->refy, sizeof ( PLINT ) );
305 
306  wr_data( pls, &text->unicode_array_len, sizeof ( PLINT ) );
307  if ( text->unicode_array_len )
308  wr_data( pls, text->unicode_array, sizeof ( PLUNICODE ) * text->unicode_array_len );
309 }
310 
311 //--------------------------------------------------------------------------
312 // plbuf_text_unicode()
313 //
314 // Handle text buffering for the new unicode pathway.
315 //--------------------------------------------------------------------------
316 
317 static void
319 {
320  PLUNICODE fci;
321 
322  dbug_enter( "plbuf_text" );
323 
324  // Retrieve the font characterization integer
325  plgfci( &fci );
326 
327  // Write the text information
328 
329  wr_data( pls, &fci, sizeof ( PLUNICODE ) );
330 
331  wr_data( pls, &pls->chrht, sizeof ( PLFLT ) );
332  wr_data( pls, &pls->diorot, sizeof ( PLFLT ) );
333  wr_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
334  wr_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
335  wr_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
336  wr_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
337 
338  wr_data( pls, &text->base, sizeof ( PLINT ) );
339  wr_data( pls, &text->just, sizeof ( PLFLT ) );
340  wr_data( pls, text->xform, sizeof ( PLFLT ) * 4 );
341  wr_data( pls, &text->x, sizeof ( PLINT ) );
342  wr_data( pls, &text->y, sizeof ( PLINT ) );
343  wr_data( pls, &text->refx, sizeof ( PLINT ) );
344  wr_data( pls, &text->refy, sizeof ( PLINT ) );
345 
346  wr_data( pls, &text->n_fci, sizeof ( PLUNICODE ) );
347  wr_data( pls, &text->n_char, sizeof ( PLUNICODE ) );
348  wr_data( pls, &text->n_ctrl_char, sizeof ( PLINT ) );
349 
350  wr_data( pls, &text->unicode_array_len, sizeof ( PLINT ) );
351 }
352 
353 
354 //--------------------------------------------------------------------------
355 // plbuf_esc()
356 //
357 // Escape function. Note that any data written must be in device
358 // independent form to maintain the transportability of the metafile.
359 //
360 // Functions:
361 //
362 // PLESC_FILL Fill polygon
363 // PLESC_SWIN Set plot window parameters
364 // PLESC_IMAGE Draw image
365 // PLESC_HAS_TEXT Draw PostScript text
366 // PLESC_CLEAR Clear Background
367 // PLESC_START_RASTERIZE
368 // PLESC_END_RASTERIZE Start and stop rasterization
369 //--------------------------------------------------------------------------
370 
371 void
372 plbuf_esc( PLStream *pls, PLINT op, void *ptr )
373 {
374  dbug_enter( "plbuf_esc" );
375 
376  wr_command( pls, (U_CHAR) ESCAPE );
377  wr_command( pls, (U_CHAR) op );
378 
379  switch ( op )
380  {
381  case PLESC_FILL:
382  plbuf_fill( pls );
383  break;
384  case PLESC_SWIN:
385  plbuf_swin( pls, (PLWindow *) ptr );
386  break;
387  case PLESC_IMAGE:
388  plbuf_image( pls, (IMG_DT *) ptr );
389  break;
390  case PLESC_HAS_TEXT:
391  if ( ptr != NULL ) // Check required by GCW driver, please don't remove
392  plbuf_text( pls, (EscText *) ptr );
393  break;
394  case PLESC_BEGIN_TEXT:
395  case PLESC_TEXT_CHAR:
396  case PLESC_CONTROL_CHAR:
397  case PLESC_END_TEXT:
398  plbuf_text_unicode( pls, (EscText *) ptr );
399  break;
400 #if 0
401  // These are a no-op. They just need an entry in the buffer.
402  case PLESC_CLEAR:
404  case PLESC_END_RASTERIZE:
405  break;
406 #endif
407  }
408 }
409 
410 //--------------------------------------------------------------------------
411 // plbuf_fill()
412 //
413 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
414 //--------------------------------------------------------------------------
415 
416 static void
418 {
419  dbug_enter( "plbuf_fill" );
420 
421  wr_data( pls, &pls->dev_npts, sizeof ( PLINT ) );
422  wr_data( pls, pls->dev_x, sizeof ( short ) * (size_t) pls->dev_npts );
423  wr_data( pls, pls->dev_y, sizeof ( short ) * (size_t) pls->dev_npts );
424 }
425 
426 //--------------------------------------------------------------------------
427 // plbuf_swin()
428 //
429 // Set up plot window parameters.
430 //--------------------------------------------------------------------------
431 
432 static void
433 plbuf_swin( PLStream *pls, PLWindow *plwin )
434 {
435  wr_data( pls, &plwin->dxmi, sizeof ( PLFLT ) );
436  wr_data( pls, &plwin->dxma, sizeof ( PLFLT ) );
437  wr_data( pls, &plwin->dymi, sizeof ( PLFLT ) );
438  wr_data( pls, &plwin->dyma, sizeof ( PLFLT ) );
439 
440  wr_data( pls, &plwin->wxmi, sizeof ( PLFLT ) );
441  wr_data( pls, &plwin->wxma, sizeof ( PLFLT ) );
442  wr_data( pls, &plwin->wymi, sizeof ( PLFLT ) );
443  wr_data( pls, &plwin->wyma, sizeof ( PLFLT ) );
444 }
445 
446 //--------------------------------------------------------------------------
447 // Routines to read from & process the plot buffer.
448 //--------------------------------------------------------------------------
449 
450 //--------------------------------------------------------------------------
451 // rdbuf_init()
452 //
453 // Initialize device.
454 //--------------------------------------------------------------------------
455 
456 static void
458 {
459  dbug_enter( "rdbuf_init" );
460 }
461 
462 //--------------------------------------------------------------------------
463 // rdbuf_line()
464 //
465 // Draw a line in the current color from (x1,y1) to (x2,y2).
466 //--------------------------------------------------------------------------
467 
468 static void
470 {
471  short xpl[2], ypl[2];
472  PLINT npts = 2;
473 
474  dbug_enter( "rdbuf_line" );
475 
476  rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
477  rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
478 
479  plP_line( xpl, ypl );
480 }
481 
482 //--------------------------------------------------------------------------
483 // rdbuf_polyline()
484 //
485 // Draw a polyline in the current color.
486 //--------------------------------------------------------------------------
487 
488 static void
490 {
491  short _xpl[PL_MAXPOLY], _ypl[PL_MAXPOLY];
492  short *xpl, *ypl;
493  PLINT npts;
494 
495  dbug_enter( "rdbuf_polyline" );
496 
497  rd_data( pls, &npts, sizeof ( PLINT ) );
498 
499  if ( npts > PL_MAXPOLY )
500  {
501  xpl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
502  ypl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
503 
504  if ( ( xpl == NULL ) || ( ypl == NULL ) )
505  {
506  plexit( "rdbuf_polyline: Insufficient memory for large polyline" );
507  }
508  }
509  else
510  {
511  xpl = _xpl;
512  ypl = _ypl;
513  }
514 
515 
516  rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
517  rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
518 
519  plP_polyline( xpl, ypl, npts );
520 
521  if ( npts > PL_MAXPOLY )
522  {
523  free( xpl );
524  free( ypl );
525  }
526 }
527 
528 //--------------------------------------------------------------------------
529 // rdbuf_eop()
530 //
531 // End of page.
532 //--------------------------------------------------------------------------
533 
534 static void
536 {
537  dbug_enter( "rdbuf_eop" );
538 }
539 
540 //--------------------------------------------------------------------------
541 // rdbuf_bop()
542 //
543 // Set up for the next page.
544 //--------------------------------------------------------------------------
545 
546 static void
548 {
549  dbug_enter( "rdbuf_bop" );
550 
551  pls->nplwin = 0;
552 }
553 
554 //--------------------------------------------------------------------------
555 // rdbuf_state()
556 //
557 // Handle change in PLStream state (color, pen width, fill attribute, etc).
558 //--------------------------------------------------------------------------
559 
560 static void
562 {
563  U_CHAR op;
564 
565  dbug_enter( "rdbuf_state" );
566 
567  rd_data( pls, &op, sizeof ( U_CHAR ) );
568 
569  switch ( op )
570  {
571  case PLSTATE_WIDTH: {
572  rd_data( pls, &( pls->width ), sizeof ( pls->width ) );
574 
575  break;
576  }
577 
578  case PLSTATE_COLOR0: {
579  short icol0;
580  U_CHAR r, g, b;
581  PLFLT a;
582 
583  rd_data( pls, &icol0, sizeof ( short ) );
584  if ( icol0 == PL_RGB_COLOR )
585  {
586  rd_data( pls, &r, sizeof ( U_CHAR ) );
587  rd_data( pls, &g, sizeof ( U_CHAR ) );
588  rd_data( pls, &b, sizeof ( U_CHAR ) );
589  a = 1.0;
590  }
591  else
592  {
593  if ( (int) icol0 >= pls->ncol0 )
594  {
595  char buffer[256];
596  snprintf( buffer, 256, "rdbuf_state: Invalid color map entry: %d", (int) icol0 );
597  plabort( buffer );
598  return;
599  }
600  r = pls->cmap0[icol0].r;
601  g = pls->cmap0[icol0].g;
602  b = pls->cmap0[icol0].b;
603  a = pls->cmap0[icol0].a;
604  }
605  pls->icol0 = icol0;
606  pls->curcolor.r = r;
607  pls->curcolor.g = g;
608  pls->curcolor.b = b;
609  pls->curcolor.a = a;
610 
612  break;
613  }
614 
615  case PLSTATE_COLOR1: {
616  short icol1;
617 
618  rd_data( pls, &icol1, sizeof ( short ) );
619 
620  pls->icol1 = icol1;
621  pls->curcolor.r = pls->cmap1[icol1].r;
622  pls->curcolor.g = pls->cmap1[icol1].g;
623  pls->curcolor.b = pls->cmap1[icol1].b;
624  pls->curcolor.a = pls->cmap1[icol1].a;
625 
627  break;
628  }
629 
630  case PLSTATE_FILL: {
631  signed char patt;
632 
633  rd_data( pls, &patt, sizeof ( signed char ) );
634 
635  pls->patt = patt;
637  break;
638  }
639  }
640 }
641 
642 //--------------------------------------------------------------------------
643 // rdbuf_esc()
644 //
645 // Escape function.
646 // Must fill data structure with whatever data that was written,
647 // then call escape function.
648 //
649 // Note: it is best to only call the escape function for op-codes that
650 // are known to be supported.
651 //
652 // Functions:
653 //
654 // PLESC_FILL Fill polygon
655 // PLESC_SWIN Set plot window parameters
656 // PLESC_IMAGE Draw image
657 // PLESC_HAS_TEXT Draw PostScript text
658 // PLESC_BEGIN_TEXT Commands for the alternative unicode text handling path
659 // PLESC_TEXT_CHAR
660 // PLESC_CONTROL_CHAR
661 // PLESC_END_TEXT
662 // PLESC_CLEAR Clear Background
663 //--------------------------------------------------------------------------
664 
665 static void
666 rdbuf_image( PLStream *pls );
667 
668 static void
669 rdbuf_text( PLStream *pls );
670 
671 static void
672 rdbuf_text_unicode( PLINT op, PLStream *pls );
673 
674 static void
676 {
677  U_CHAR op;
678 
679  dbug_enter( "rdbuf_esc" );
680 
681  rd_data( pls, &op, sizeof ( U_CHAR ) );
682 
683  switch ( op )
684  {
685  case PLESC_FILL:
686  rdbuf_fill( pls );
687  break;
688  case PLESC_SWIN:
689  rdbuf_swin( pls );
690  break;
691  case PLESC_IMAGE:
692  rdbuf_image( pls );
693  break;
694  case PLESC_HAS_TEXT:
695  rdbuf_text( pls );
696  break;
697  case PLESC_BEGIN_TEXT:
698  case PLESC_TEXT_CHAR:
699  case PLESC_CONTROL_CHAR:
700  case PLESC_END_TEXT:
701  rdbuf_text_unicode( op, pls );
702  break;
703  case PLESC_CLEAR:
704  plP_esc( PLESC_CLEAR, NULL );
705  break;
708  break;
709  case PLESC_END_RASTERIZE:
710  plP_esc( PLESC_END_RASTERIZE, NULL );
711  break;
712  }
713 }
714 
715 //--------------------------------------------------------------------------
716 // rdbuf_fill()
717 //
718 // Fill polygon described by input points.
719 //--------------------------------------------------------------------------
720 
721 static void
723 {
724  short _xpl[PL_MAXPOLY], _ypl[PL_MAXPOLY];
725  short *xpl, *ypl;
726  PLINT npts;
727 
728  dbug_enter( "rdbuf_fill" );
729 
730  rd_data( pls, &npts, sizeof ( PLINT ) );
731 
732  if ( npts > PL_MAXPOLY )
733  {
734  xpl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
735  ypl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
736 
737  if ( ( xpl == NULL ) || ( ypl == NULL ) )
738  {
739  plexit( "rdbuf_polyline: Insufficient memory for large polyline" );
740  }
741  }
742  else
743  {
744  xpl = _xpl;
745  ypl = _ypl;
746  }
747 
748  rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
749  rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
750 
751  plP_fill( xpl, ypl, npts );
752 
753  if ( npts > PL_MAXPOLY )
754  {
755  free( xpl );
756  free( ypl );
757  }
758 }
759 
760 //--------------------------------------------------------------------------
761 // rdbuf_image()
762 //
763 // .
764 //--------------------------------------------------------------------------
765 
766 static void
768 {
769  // Unnecessarily initialize dev_iy and dev_z to quiet -O1
770  // -Wuninitialized warnings which are false alarms. (If something
771  // goes wrong with the dev_ix malloc below any further use of
772  // dev_iy and dev_z does not occur. Similarly, if something goes
773  // wrong with the dev_iy malloc below any further use of dev_z
774  // does not occur.)
775  short *dev_ix, *dev_iy = NULL;
776  unsigned short *dev_z = NULL, dev_zmin, dev_zmax;
777  PLINT nptsX, nptsY, npts;
778  PLFLT xmin, ymin, dx, dy;
779 
780  dbug_enter( "rdbuf_image" );
781 
782  rd_data( pls, &nptsX, sizeof ( PLINT ) );
783  rd_data( pls, &nptsY, sizeof ( PLINT ) );
784  npts = nptsX * nptsY;
785 
786  rd_data( pls, &xmin, sizeof ( PLFLT ) );
787  rd_data( pls, &ymin, sizeof ( PLFLT ) );
788  rd_data( pls, &dx, sizeof ( PLFLT ) );
789  rd_data( pls, &dy, sizeof ( PLFLT ) );
790 
791  rd_data( pls, &dev_zmin, sizeof ( short ) );
792  rd_data( pls, &dev_zmax, sizeof ( short ) );
793 
794  // NOTE: Even though for memory buffered version all the data is in memory,
795  // we still allocate and copy the data because I think that method works
796  // better in a multithreaded environment. I could be wrong.
797  //
798  if ( ( ( dev_ix = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
799  ( ( dev_iy = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
800  ( ( dev_z = (unsigned short *) malloc( (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) * sizeof ( unsigned short ) ) ) == NULL ) )
801  plexit( "rdbuf_image: Insufficient memory" );
802 
803  rd_data( pls, dev_ix, sizeof ( short ) * (size_t) npts );
804  rd_data( pls, dev_iy, sizeof ( short ) * (size_t) npts );
805  rd_data( pls, dev_z, sizeof ( unsigned short ) * (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) );
806 
807  //
808  // COMMENTED OUT by Hezekiah Carty
809  // Commented (hopefullly temporarily) until the dev_fastimg rendering
810  // path can be updated to support the new plimage internals. In the
811  // meantime this function is not actually used so the issue of how to
812  // update the code to support the new interface can be ignored.
813  //
814  //plP_image(dev_ix, dev_iy, dev_z, nptsX, nptsY, xmin, ymin, dx, dy, dev_zmin, dev_zmax);
815 
816  free( dev_ix );
817  free( dev_iy );
818  free( dev_z );
819 }
820 
821 //--------------------------------------------------------------------------
822 // rdbuf_swin()
823 //
824 // Set up plot window parameters.
825 //--------------------------------------------------------------------------
826 
827 static void
829 {
830  PLWindow plwin;
831 
832  rd_data( pls, &plwin.dxmi, sizeof ( PLFLT ) );
833  rd_data( pls, &plwin.dxma, sizeof ( PLFLT ) );
834  rd_data( pls, &plwin.dymi, sizeof ( PLFLT ) );
835  rd_data( pls, &plwin.dyma, sizeof ( PLFLT ) );
836 
837  rd_data( pls, &plwin.wxmi, sizeof ( PLFLT ) );
838  rd_data( pls, &plwin.wxma, sizeof ( PLFLT ) );
839  rd_data( pls, &plwin.wymi, sizeof ( PLFLT ) );
840  rd_data( pls, &plwin.wyma, sizeof ( PLFLT ) );
841 
842  plP_swin( &plwin );
843 }
844 
845 //--------------------------------------------------------------------------
846 // rdbuf_text()
847 //
848 // Draw PostScript text.
849 //--------------------------------------------------------------------------
850 
851 static void
853 {
854  PLUNICODE( fci );
855  EscText text;
856  PLFLT xform[4];
857  PLUNICODE* unicode;
858 
859  text.xform = xform;
860 
861 
862  // Read in the data
863 
864  rd_data( pls, &fci, sizeof ( PLUNICODE ) );
865 
866  rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
867  rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
868  rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
869  rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
870  rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
871  rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
872 
873  rd_data( pls, &text.base, sizeof ( PLINT ) );
874  rd_data( pls, &text.just, sizeof ( PLFLT ) );
875  rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
876  rd_data( pls, &text.x, sizeof ( PLINT ) );
877  rd_data( pls, &text.y, sizeof ( PLINT ) );
878  rd_data( pls, &text.refx, sizeof ( PLINT ) );
879  rd_data( pls, &text.refy, sizeof ( PLINT ) );
880 
881  rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
882  if ( text.unicode_array_len )
883  {
884  if ( ( unicode = (PLUNICODE *) malloc( text.unicode_array_len * sizeof ( PLUNICODE ) ) )
885  == NULL )
886  plexit( "rdbuf_text: Insufficient memory" );
887 
888  rd_data( pls, unicode, sizeof ( PLUNICODE ) * text.unicode_array_len );
889  text.unicode_array = unicode;
890  }
891  else
892  text.unicode_array = NULL;
893 
894  // Make the call for unicode devices
895  if ( pls->dev_unicode )
896  {
897  plsfci( fci );
898  plP_esc( PLESC_HAS_TEXT, &text );
899  }
900 }
901 
902 //--------------------------------------------------------------------------
903 // rdbuf_text_unicode()
904 //
905 // Draw text for the new unicode handling pathway.
906 //--------------------------------------------------------------------------
907 
908 static void
910 {
911  PLUNICODE( fci );
912  EscText text;
913  PLFLT xform[4];
914 
915  text.xform = xform;
916 
917 
918  // Read in the data
919 
920  rd_data( pls, &fci, sizeof ( PLUNICODE ) );
921 
922  rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
923  rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
924  rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
925  rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
926  rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
927  rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
928 
929  rd_data( pls, &text.base, sizeof ( PLINT ) );
930  rd_data( pls, &text.just, sizeof ( PLFLT ) );
931  rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
932  rd_data( pls, &text.x, sizeof ( PLINT ) );
933  rd_data( pls, &text.y, sizeof ( PLINT ) );
934  rd_data( pls, &text.refx, sizeof ( PLINT ) );
935  rd_data( pls, &text.refy, sizeof ( PLINT ) );
936 
937  rd_data( pls, &text.n_fci, sizeof ( PLUNICODE ) );
938  rd_data( pls, &text.n_char, sizeof ( PLUNICODE ) );
939  rd_data( pls, &text.n_ctrl_char, sizeof ( PLINT ) );
940 
941  rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
942 
943  if ( pls->dev_unicode )
944  {
945  plsfci( fci );
946  plP_esc( op, &text );
947  }
948 }
949 
950 //--------------------------------------------------------------------------
951 // plRemakePlot()
952 //
953 // Rebuilds plot from plot buffer, usually in response to a window
954 // resize or exposure event.
955 //--------------------------------------------------------------------------
956 
957 void
959 {
960  U_CHAR c;
961  int plbuf_status;
962  PLStream *save_pls;
963 
964  dbug_enter( "plRemakePlot" );
965 
966  // Change the status of the flags before checking for a buffer.
967  // Actually, more thought is needed if we want to support multithreaded
968  // code correctly, specifically the case where two threads are using
969  // the same plot stream (e.g. one thread is drawing the plot and another
970  // thread is processing window manager messages).
971  //
972  plbuf_status = pls->plbuf_write;
973  pls->plbuf_write = FALSE;
974  pls->plbuf_read = TRUE;
975 
976 #ifdef BUFFERED_FILE
977  if ( pls->plbufFile )
978  {
979  rewind( pls->plbufFile );
980 #else
981  if ( pls->plbuf_buffer )
982  {
983  pls->plbuf_readpos = 0;
984 #endif
985  // Need to change where plsc points to before processing the commands.
986  // If we have multiple plot streams, this will prevent the commands from
987  // going to the wrong plot stream.
988  //
989  save_pls = plsc;
990  plsc = pls;
991 
992  while ( rd_command( pls, &c ) )
993  {
994  plbuf_control( pls, c );
995  }
996 
997  plsc = save_pls;
998  }
999 
1000  pls->plbuf_read = FALSE;
1001  pls->plbuf_write = plbuf_status;
1002 }
1003 
1004 //--------------------------------------------------------------------------
1005 // plbuf_control()
1006 //
1007 // Processes commands read from the plot buffer.
1008 //--------------------------------------------------------------------------
1009 
1010 static void
1012 {
1013  static U_CHAR c_old = 0;
1014 
1015  dbug_enter( "plbuf_control" );
1016 
1017  switch ( (int) c )
1018  {
1019  case INITIALIZE:
1020  rdbuf_init( pls );
1021  break;
1022 
1023  case EOP:
1024  rdbuf_eop( pls );
1025  break;
1026 
1027  case BOP:
1028  rdbuf_bop( pls );
1029  break;
1030 
1031  case CHANGE_STATE:
1032  rdbuf_state( pls );
1033  break;
1034 
1035  case LINE:
1036  rdbuf_line( pls );
1037  break;
1038 
1039  case POLYLINE:
1040  rdbuf_polyline( pls );
1041  break;
1042 
1043  case ESCAPE:
1044  rdbuf_esc( pls );
1045  break;
1046 
1047  default:
1048  pldebug( "plbuf_control", "Unrecognized command %d, previous %d\n", c, c_old );
1049  }
1050  c_old = c;
1051 }
1052 
1053 //--------------------------------------------------------------------------
1054 // rd_command()
1055 //
1056 // Read & return the next command
1057 //--------------------------------------------------------------------------
1058 
1059 static int
1061 {
1062  int count;
1063 
1064 #ifdef BUFFERED_FILE
1065  count = fread( p_c, sizeof ( U_CHAR ), 1, pls->plbufFile );
1066 #else
1067  if ( pls->plbuf_readpos < pls->plbuf_top )
1068  {
1069  *p_c = *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos );
1070  pls->plbuf_readpos += sizeof ( U_CHAR );
1071  count = sizeof ( U_CHAR );
1072  }
1073  else
1074  {
1075  count = 0;
1076  }
1077 #endif
1078  return ( count );
1079 }
1080 
1081 //--------------------------------------------------------------------------
1082 // rd_data()
1083 //
1084 // Read the data associated with the command
1085 //--------------------------------------------------------------------------
1086 
1087 static void
1088 rd_data( PLStream *pls, void *buf, size_t buf_size )
1089 {
1090 #ifdef BUFFERED_FILE
1091  plio_fread( buf, buf_size, 1, pls->plbufFile );
1092 #else
1093 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
1094 // then this code will have problems. A better approach might be to use
1095 // uint8_t from <stdint.h> but I do not know how portable that approach is
1096 //
1097  memcpy( buf, (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos, buf_size );
1098  pls->plbuf_readpos += buf_size;
1099 #endif
1100 }
1101 
1102 //--------------------------------------------------------------------------
1103 // wr_command()
1104 //
1105 // Write the next command
1106 //--------------------------------------------------------------------------
1107 
1108 static void
1110 {
1111 #ifdef BUFFERED_FILE
1112  plio_fwrite( &c1, sizeof ( U_CHAR ), 1, pls->plbufFile );
1113 #else
1114  if ( ( pls->plbuf_top + sizeof ( U_CHAR ) ) >= pls->plbuf_buffer_size )
1115  {
1116  // Not enough space, need to grow the buffer
1117  pls->plbuf_buffer_size += pls->plbuf_buffer_grow;
1118 
1119  if ( pls->verbose )
1120  printf( "Growing buffer to %d KB\n", (int) ( pls->plbuf_buffer_size / 1024 ) );
1121  if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
1122  plexit( "plbuf wr_data: Plot buffer grow failed" );
1123  }
1124 
1125  *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top ) = c;
1126  pls->plbuf_top += sizeof ( U_CHAR );
1127 #endif
1128 }
1129 
1130 //--------------------------------------------------------------------------
1131 // wr_data()
1132 //
1133 // Write the data associated with a command
1134 //--------------------------------------------------------------------------
1135 
1136 static void
1137 wr_data( PLStream *pls, void *buf, size_t buf_size )
1138 {
1139 #ifdef BUFFERED_FILE
1140  plio_fwrite( buf, buf_size, 1, pls->plbufFile );
1141 #else
1142  if ( ( pls->plbuf_top + buf_size ) >= pls->plbuf_buffer_size )
1143  {
1144  // Not enough space, need to grow the buffer
1145  // Must make sure the increase is enough for this data
1146  pls->plbuf_buffer_size += pls->plbuf_buffer_grow *
1147  ( ( pls->plbuf_top + buf_size - pls->plbuf_buffer_size ) /
1148  pls->plbuf_buffer_grow + 1 );
1149  while ( pls->plbuf_top + buf_size >= pls->plbuf_buffer_size )
1150  ;
1151 
1152  if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
1153  plexit( "plbuf wr_data: Plot buffer grow failed" );
1154  }
1155 
1156 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
1157 // then this code will have problems. A better approach might be to use
1158 // uint8_t from <stdint.h> but I do not know how portable that approach is
1159 //
1160  memcpy( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top, buf, buf_size );
1161  pls->plbuf_top += buf_size;
1162 #endif
1163 }
1164 
1165 // plbuf_save(state)
1166 //
1167 // Saves the current state of the plot into a save buffer.
1168 // This code was originally in gcw.c and gcw-lib.c. The original
1169 // code used a temporary file for the plot buffer and memory
1170 // to perserve colormaps. That method does not offer a clean
1171 // break between using memory buffers and file buffers. This
1172 // function preserves the same functionality by returning a data
1173 // structure that saves the plot buffer and colormaps seperately.
1174 //
1175 // The caller passes an existing save buffer for reuse or NULL
1176 // to force the allocation of a new buffer. Since one malloc()
1177 // is used for everything, the entire save buffer can be freed
1178 // with one free() call.
1179 //
1180 //
1182 {
1186 };
1187 
1188 struct _state
1189 {
1190  size_t size; // Size of the save buffer
1191  int valid; // Flag to indicate a valid save state
1192 #ifdef BUFFERED_FILE
1193  FILE *plbufFile;
1194 #else
1197  size_t plbuf_top;
1199 #endif
1201 };
1202 
1203 void * plbuf_save( PLStream *pls, void *state )
1204 {
1205  size_t save_size;
1206  struct _state *plot_state = (struct _state *) state;
1207  PLINT i;
1208  U_CHAR *buf; // Assume that this is byte-sized
1209 
1210  if ( pls->plbuf_write )
1211  {
1212  pls->plbuf_write = FALSE;
1213  pls->plbuf_read = TRUE;
1214 
1215  // Determine the size of the buffer required to save everything. We
1216  // assume that there are only two colormaps, but have written the code
1217  // that more than two can be handled with minimal changes.
1218  //
1219  save_size = sizeof ( struct _state )
1220  + 2 * sizeof ( struct _color_map )
1221  + (size_t) ( pls->ncol0 ) * sizeof ( PLColor )
1222  + (size_t) ( pls->ncol1 ) * sizeof ( PLColor );
1223 
1224 #ifndef BUFFERED_FILE
1225  // Only copy as much of the plot buffer that is being used
1226  save_size += pls->plbuf_top;
1227 #endif
1228 
1229  // If a buffer exists, determine if we need to resize it
1230  if ( state != NULL )
1231  {
1232  // We have a save buffer, is it smaller than the current size requirement?
1233  if ( plot_state->size < save_size )
1234  {
1235  // Yes, reallocate a larger one
1236  if ( ( plot_state = (struct _state *) realloc( state, save_size ) ) == NULL )
1237  {
1238  // NOTE: If realloc fails, then plot_state ill be NULL.
1239  // This will leave the original buffer untouched, thus we
1240  // mark it as invalid and return it back to the caller.
1241  //
1242  plwarn( "plbuf: Unable to reallocate sufficient memory to save state" );
1243  plot_state->valid = 0;
1244 
1245  return state;
1246  }
1247  plot_state->size = save_size;
1248  }
1249  }
1250  else
1251  {
1252  // A buffer does not exist, so we need to allocate one
1253  if ( ( plot_state = (struct _state *) malloc( save_size ) ) == NULL )
1254  {
1255  plwarn( "plbuf: Unable to allocate sufficient memory to save state" );
1256 
1257  return NULL;
1258  }
1259  plot_state->size = save_size;
1260 
1261 #ifdef BUFFERED_FILE
1262  // Make sure the FILE pointer is NULL in order to preven bad things from happening...
1263  plot_state->plbufFile = NULL;
1264 #endif
1265  }
1266 
1267  // At this point we have an appropriately sized save buffer.
1268  // We need to invalidate the state of the save buffer, since it
1269  // will not be valid until after everything is copied. We use
1270  // this approach vice freeing the memory and returning a NULL pointer
1271  // in order to prevent allocating and freeing memory needlessly.
1272  //
1273  plot_state->valid = 0;
1274 
1275  // Point buf to the space after the struct _state
1276  buf = (U_CHAR *) ( plot_state + 1 );
1277 
1278 #ifdef BUFFERED_FILE
1279  // Remove the old tempfile, if it exists
1280  if ( plot_state->plbufFile != NULL )
1281  {
1282  fclose( plot_state->plbufFile );
1283  }
1284 
1285  // Copy the plot buffer to a tempfile
1286  if ( ( plot_state->plbufFile = pl_create_tempfile( NULL ) ) == NULL )
1287  {
1288  // Throw a warning since this might be a permissions problem
1289  // and we may not want to force an exit
1290  //
1291  plwarn( "plbuf: Unable to open temporary file to save state" );
1292  return (void *) plot_state;
1293  }
1294  else
1295  {
1296  U_CHAR tmp;
1297 
1298  rewind( pls->plbufFile );
1299  while ( count = fread( &tmp, sizeof ( U_CHAR ), 1, pls->plbufFile ) )
1300  {
1301  if ( fwrite( &tmp, sizeof ( U_CHAR ), 1, plot_state->plbufFile ) != count )
1302  {
1303  // Throw a warning since this might be a permissions problem
1304  // and we may not want to force an exit
1305  //
1306  plwarn( "plbuf: Unable to write to temporary file" );
1307  fclose( plot_state->plbufFile );
1308  plot_state->plbufFile = NULL;
1309  return (void *) plot_state;
1310  }
1311  }
1312  }
1313 #else
1314  // Again, note, that we only copy the portion of the plot buffer that is being used
1315  plot_state->plbuf_buffer_size = pls->plbuf_top;
1316  plot_state->plbuf_top = pls->plbuf_top;
1317  plot_state->plbuf_readpos = 0;
1318 
1319  // Create a pointer that points in the space we allocated after struct _state
1320  plot_state->plbuf_buffer = (void *) buf;
1321  buf += pls->plbuf_top;
1322 
1323  // Copy the plot buffer to our new buffer. Again, I must stress, that we only
1324  // are copying the portion of the plot buffer that is being used
1325  //
1326  if ( memcpy( plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL )
1327  {
1328  // This should never be NULL
1329  plwarn( "plbuf: Got a NULL in memcpy!" );
1330  return (void *) plot_state;
1331  }
1332 #endif
1333 
1334  pls->plbuf_write = TRUE;
1335  pls->plbuf_read = FALSE;
1336 
1337  // Save the colormaps. First create a pointer that points in the space we allocated
1338  // after the plot buffer
1339  plot_state->color_map = (struct _color_map *) buf;
1340  buf += sizeof ( struct _color_map ) * 2;
1341 
1342  // Then we need to make space for the colormaps themselves
1343  plot_state->color_map[0].cmap = (PLColor *) buf;
1344  buf += sizeof ( PLColor ) * (size_t) ( pls->ncol0 );
1345  plot_state->color_map[1].cmap = (PLColor *) buf;
1346  buf += sizeof ( PLColor ) * (size_t) ( pls->ncol1 );
1347 
1348  // Save cmap 0
1349  plot_state->color_map[0].icol = pls->icol0;
1350  plot_state->color_map[0].ncol = pls->ncol0;
1351  for ( i = 0; i < pls->ncol0; i++ )
1352  {
1353  pl_cpcolor( &( plot_state->color_map[0].cmap[i] ), &pls->cmap0[i] );
1354  }
1355 
1356  // Save cmap 1
1357  plot_state->color_map[1].icol = pls->icol1;
1358  plot_state->color_map[1].ncol = pls->ncol1;
1359  for ( i = 0; i < pls->ncol1; i++ )
1360  {
1361  pl_cpcolor( &( plot_state->color_map[1].cmap[i] ), &pls->cmap1[i] );
1362  }
1363 
1364  plot_state->valid = 1;
1365  return (void *) plot_state;
1366  }
1367 
1368  return NULL;
1369 }
1370 
1371 // plbuf_restore(PLStream *, state)
1372 //
1373 // Restores the passed state
1374 //
1375 void plbuf_restore( PLStream *pls, void *state )
1376 {
1377  struct _state *new_state = (struct _state *) state;
1378 
1379 #ifdef BUFFERED_FILE
1380  pls->plbufFile = new_state->save_file;
1381 #else
1382  pls->plbuf_buffer = new_state->plbuf_buffer;
1383  pls->plbuf_buffer_size = new_state->plbuf_buffer_size;
1384  pls->plbuf_top = new_state->plbuf_top;
1385  pls->plbuf_readpos = new_state->plbuf_readpos;
1386 #endif
1387  // cmap 0
1388  pls->cmap0 = new_state->color_map[0].cmap;
1389  pls->icol0 = new_state->color_map[0].icol;
1390  pls->ncol0 = new_state->color_map[0].ncol;
1391  // cmap 1
1392  pls->cmap1 = new_state->color_map[1].cmap;
1393  pls->icol1 = new_state->color_map[1].icol;
1394  pls->ncol1 = new_state->color_map[1].ncol;
1395 }
1396 
1397 // plbuf_switch(PLStream *, state)
1398 //
1399 // Makes the passed state the current one. Preserves the previous state
1400 // by returning a save buffer.
1401 //
1402 // NOTE: The current implementation can cause a memory leak under the
1403 // following scenario:
1404 // 1) plbuf_save() is called
1405 // 2) plbuf_switch() is called
1406 // 3) Commands are called which cause the plot buffer to grow
1407 // 4) plbuf_swtich() is called
1408 //
1409 void * plbuf_switch( PLStream *pls, void *state )
1410 {
1411  struct _state *new_state = (struct _state *) state;
1412  struct _state *prev_state;
1413  size_t save_size;
1414 
1415  // No saved state was passed, return a NULL--we hope the caller
1416  // is smart enough to notice
1417  //
1418  if ( state == NULL )
1419  return NULL;
1420 
1421  if ( !new_state->valid )
1422  {
1423  plwarn( "plbuf: Attempting to switch to an invalid saved state" );
1424  return NULL;
1425  }
1426 
1427  save_size = sizeof ( struct _state )
1428  + 2 * sizeof ( struct _color_map );
1429 
1430  if ( ( prev_state = (struct _state *) malloc( save_size ) ) == NULL )
1431  {
1432  plwarn( "plbuf: Unable to allocate memory to save state" );
1433  return NULL;
1434  }
1435 
1436  // Set some housekeeping variables
1437  prev_state->size = save_size;
1438  prev_state->valid = 1;
1439 
1440  // Preserve the existing state
1441 #ifdef BUFFERED_FILE
1442  prev_state->plbufFile = pls->plbufFile;
1443 #else
1444  prev_state->plbuf_buffer = pls->plbuf_buffer;
1445  prev_state->plbuf_buffer_size = pls->plbuf_buffer_size;
1446  prev_state->plbuf_top = pls->plbuf_top;
1447  prev_state->plbuf_readpos = pls->plbuf_readpos;
1448 #endif
1449  // cmap 0
1450  prev_state->color_map[0].cmap = pls->cmap0;
1451  prev_state->color_map[0].icol = pls->icol0;
1452  prev_state->color_map[0].ncol = pls->ncol0;
1453  // cmap 1
1454  prev_state->color_map[1].cmap = pls->cmap1;
1455  prev_state->color_map[1].icol = pls->icol1;
1456  prev_state->color_map[1].ncol = pls->ncol1;
1457 
1458  plbuf_restore( pls, new_state );
1459 
1460  return (void *) prev_state;
1461 }
1462 
1463