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  U_CHAR width;
573 
574  rd_data( pls, &width, sizeof ( U_CHAR ) );
575  pls->width = width;
577 
578  break;
579  }
580 
581  case PLSTATE_COLOR0: {
582  short icol0;
583  U_CHAR r, g, b;
584  PLFLT a;
585 
586  rd_data( pls, &icol0, sizeof ( short ) );
587  if ( icol0 == PL_RGB_COLOR )
588  {
589  rd_data( pls, &r, sizeof ( U_CHAR ) );
590  rd_data( pls, &g, sizeof ( U_CHAR ) );
591  rd_data( pls, &b, sizeof ( U_CHAR ) );
592  a = 1.0;
593  }
594  else
595  {
596  if ( (int) icol0 >= pls->ncol0 )
597  {
598  char buffer[256];
599  snprintf( buffer, 256, "rdbuf_state: Invalid color map entry: %d", (int) icol0 );
600  plabort( buffer );
601  return;
602  }
603  r = pls->cmap0[icol0].r;
604  g = pls->cmap0[icol0].g;
605  b = pls->cmap0[icol0].b;
606  a = pls->cmap0[icol0].a;
607  }
608  pls->icol0 = icol0;
609  pls->curcolor.r = r;
610  pls->curcolor.g = g;
611  pls->curcolor.b = b;
612  pls->curcolor.a = a;
613 
615  break;
616  }
617 
618  case PLSTATE_COLOR1: {
619  short icol1;
620 
621  rd_data( pls, &icol1, sizeof ( short ) );
622 
623  pls->icol1 = icol1;
624  pls->curcolor.r = pls->cmap1[icol1].r;
625  pls->curcolor.g = pls->cmap1[icol1].g;
626  pls->curcolor.b = pls->cmap1[icol1].b;
627  pls->curcolor.a = pls->cmap1[icol1].a;
628 
630  break;
631  }
632 
633  case PLSTATE_FILL: {
634  signed char patt;
635 
636  rd_data( pls, &patt, sizeof ( signed char ) );
637 
638  pls->patt = patt;
640  break;
641  }
642  }
643 }
644 
645 //--------------------------------------------------------------------------
646 // rdbuf_esc()
647 //
648 // Escape function.
649 // Must fill data structure with whatever data that was written,
650 // then call escape function.
651 //
652 // Note: it is best to only call the escape function for op-codes that
653 // are known to be supported.
654 //
655 // Functions:
656 //
657 // PLESC_FILL Fill polygon
658 // PLESC_SWIN Set plot window parameters
659 // PLESC_IMAGE Draw image
660 // PLESC_HAS_TEXT Draw PostScript text
661 // PLESC_BEGIN_TEXT Commands for the alternative unicode text handling path
662 // PLESC_TEXT_CHAR
663 // PLESC_CONTROL_CHAR
664 // PLESC_END_TEXT
665 // PLESC_CLEAR Clear Background
666 //--------------------------------------------------------------------------
667 
668 static void
669 rdbuf_image( PLStream *pls );
670 
671 static void
672 rdbuf_text( PLStream *pls );
673 
674 static void
675 rdbuf_text_unicode( PLINT op, PLStream *pls );
676 
677 static void
679 {
680  U_CHAR op;
681 
682  dbug_enter( "rdbuf_esc" );
683 
684  rd_data( pls, &op, sizeof ( U_CHAR ) );
685 
686  switch ( op )
687  {
688  case PLESC_FILL:
689  rdbuf_fill( pls );
690  break;
691  case PLESC_SWIN:
692  rdbuf_swin( pls );
693  break;
694  case PLESC_IMAGE:
695  rdbuf_image( pls );
696  break;
697  case PLESC_HAS_TEXT:
698  rdbuf_text( pls );
699  break;
700  case PLESC_BEGIN_TEXT:
701  case PLESC_TEXT_CHAR:
702  case PLESC_CONTROL_CHAR:
703  case PLESC_END_TEXT:
704  rdbuf_text_unicode( op, pls );
705  break;
706  case PLESC_CLEAR:
707  plP_esc( PLESC_CLEAR, NULL );
708  break;
711  break;
712  case PLESC_END_RASTERIZE:
713  plP_esc( PLESC_END_RASTERIZE, NULL );
714  break;
715  }
716 }
717 
718 //--------------------------------------------------------------------------
719 // rdbuf_fill()
720 //
721 // Fill polygon described by input points.
722 //--------------------------------------------------------------------------
723 
724 static void
726 {
727  short _xpl[PL_MAXPOLY], _ypl[PL_MAXPOLY];
728  short *xpl, *ypl;
729  PLINT npts;
730 
731  dbug_enter( "rdbuf_fill" );
732 
733  rd_data( pls, &npts, sizeof ( PLINT ) );
734 
735  if ( npts > PL_MAXPOLY )
736  {
737  xpl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
738  ypl = (short *) malloc( (size_t) ( npts + 1 ) * sizeof ( short ) );
739 
740  if ( ( xpl == NULL ) || ( ypl == NULL ) )
741  {
742  plexit( "rdbuf_polyline: Insufficient memory for large polyline" );
743  }
744  }
745  else
746  {
747  xpl = _xpl;
748  ypl = _ypl;
749  }
750 
751  rd_data( pls, xpl, sizeof ( short ) * (size_t) npts );
752  rd_data( pls, ypl, sizeof ( short ) * (size_t) npts );
753 
754  plP_fill( xpl, ypl, npts );
755 
756  if ( npts > PL_MAXPOLY )
757  {
758  free( xpl );
759  free( ypl );
760  }
761 }
762 
763 //--------------------------------------------------------------------------
764 // rdbuf_image()
765 //
766 // .
767 //--------------------------------------------------------------------------
768 
769 static void
771 {
772  // Unnecessarily initialize dev_iy and dev_z to quiet -O1
773  // -Wuninitialized warnings which are false alarms. (If something
774  // goes wrong with the dev_ix malloc below any further use of
775  // dev_iy and dev_z does not occur. Similarly, if something goes
776  // wrong with the dev_iy malloc below any further use of dev_z
777  // does not occur.)
778  short *dev_ix, *dev_iy = NULL;
779  unsigned short *dev_z = NULL, dev_zmin, dev_zmax;
780  PLINT nptsX, nptsY, npts;
781  PLFLT xmin, ymin, dx, dy;
782 
783  dbug_enter( "rdbuf_image" );
784 
785  rd_data( pls, &nptsX, sizeof ( PLINT ) );
786  rd_data( pls, &nptsY, sizeof ( PLINT ) );
787  npts = nptsX * nptsY;
788 
789  rd_data( pls, &xmin, sizeof ( PLFLT ) );
790  rd_data( pls, &ymin, sizeof ( PLFLT ) );
791  rd_data( pls, &dx, sizeof ( PLFLT ) );
792  rd_data( pls, &dy, sizeof ( PLFLT ) );
793 
794  rd_data( pls, &dev_zmin, sizeof ( short ) );
795  rd_data( pls, &dev_zmax, sizeof ( short ) );
796 
797  // NOTE: Even though for memory buffered version all the data is in memory,
798  // we still allocate and copy the data because I think that method works
799  // better in a multithreaded environment. I could be wrong.
800  //
801  if ( ( ( dev_ix = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
802  ( ( dev_iy = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
803  ( ( dev_z = (unsigned short *) malloc( (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) * sizeof ( unsigned short ) ) ) == NULL ) )
804  plexit( "rdbuf_image: Insufficient memory" );
805 
806  rd_data( pls, dev_ix, sizeof ( short ) * (size_t) npts );
807  rd_data( pls, dev_iy, sizeof ( short ) * (size_t) npts );
808  rd_data( pls, dev_z, sizeof ( unsigned short ) * (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) );
809 
810  //
811  // COMMENTED OUT by Hezekiah Carty
812  // Commented (hopefullly temporarily) until the dev_fastimg rendering
813  // path can be updated to support the new plimage internals. In the
814  // meantime this function is not actually used so the issue of how to
815  // update the code to support the new interface can be ignored.
816  //
817  //plP_image(dev_ix, dev_iy, dev_z, nptsX, nptsY, xmin, ymin, dx, dy, dev_zmin, dev_zmax);
818 
819  free( dev_ix );
820  free( dev_iy );
821  free( dev_z );
822 }
823 
824 //--------------------------------------------------------------------------
825 // rdbuf_swin()
826 //
827 // Set up plot window parameters.
828 //--------------------------------------------------------------------------
829 
830 static void
832 {
833  PLWindow plwin;
834 
835  rd_data( pls, &plwin.dxmi, sizeof ( PLFLT ) );
836  rd_data( pls, &plwin.dxma, sizeof ( PLFLT ) );
837  rd_data( pls, &plwin.dymi, sizeof ( PLFLT ) );
838  rd_data( pls, &plwin.dyma, sizeof ( PLFLT ) );
839 
840  rd_data( pls, &plwin.wxmi, sizeof ( PLFLT ) );
841  rd_data( pls, &plwin.wxma, sizeof ( PLFLT ) );
842  rd_data( pls, &plwin.wymi, sizeof ( PLFLT ) );
843  rd_data( pls, &plwin.wyma, sizeof ( PLFLT ) );
844 
845  plP_swin( &plwin );
846 }
847 
848 //--------------------------------------------------------------------------
849 // rdbuf_text()
850 //
851 // Draw PostScript text.
852 //--------------------------------------------------------------------------
853 
854 static void
856 {
857  PLUNICODE( fci );
858  EscText text;
859  PLFLT xform[4];
860  PLUNICODE* unicode;
861 
862  text.xform = xform;
863 
864 
865  // Read in the data
866 
867  rd_data( pls, &fci, sizeof ( PLUNICODE ) );
868 
869  rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
870  rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
871  rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
872  rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
873  rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
874  rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
875 
876  rd_data( pls, &text.base, sizeof ( PLINT ) );
877  rd_data( pls, &text.just, sizeof ( PLFLT ) );
878  rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
879  rd_data( pls, &text.x, sizeof ( PLINT ) );
880  rd_data( pls, &text.y, sizeof ( PLINT ) );
881  rd_data( pls, &text.refx, sizeof ( PLINT ) );
882  rd_data( pls, &text.refy, sizeof ( PLINT ) );
883 
884  rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
885  if ( text.unicode_array_len )
886  {
887  if ( ( unicode = (PLUNICODE *) malloc( text.unicode_array_len * sizeof ( PLUNICODE ) ) )
888  == NULL )
889  plexit( "rdbuf_text: Insufficient memory" );
890 
891  rd_data( pls, unicode, sizeof ( PLUNICODE ) * text.unicode_array_len );
892  text.unicode_array = unicode;
893  }
894  else
895  text.unicode_array = NULL;
896 
897  // Make the call for unicode devices
898  if ( pls->dev_unicode )
899  {
900  plsfci( fci );
901  plP_esc( PLESC_HAS_TEXT, &text );
902  }
903 }
904 
905 //--------------------------------------------------------------------------
906 // rdbuf_text_unicode()
907 //
908 // Draw text for the new unicode handling pathway.
909 //--------------------------------------------------------------------------
910 
911 static void
913 {
914  PLUNICODE( fci );
915  EscText text;
916  PLFLT xform[4];
917 
918  text.xform = xform;
919 
920 
921  // Read in the data
922 
923  rd_data( pls, &fci, sizeof ( PLUNICODE ) );
924 
925  rd_data( pls, &pls->chrht, sizeof ( PLFLT ) );
926  rd_data( pls, &pls->diorot, sizeof ( PLFLT ) );
927  rd_data( pls, &pls->clpxmi, sizeof ( PLFLT ) );
928  rd_data( pls, &pls->clpxma, sizeof ( PLFLT ) );
929  rd_data( pls, &pls->clpymi, sizeof ( PLFLT ) );
930  rd_data( pls, &pls->clpyma, sizeof ( PLFLT ) );
931 
932  rd_data( pls, &text.base, sizeof ( PLINT ) );
933  rd_data( pls, &text.just, sizeof ( PLFLT ) );
934  rd_data( pls, text.xform, sizeof ( PLFLT ) * 4 );
935  rd_data( pls, &text.x, sizeof ( PLINT ) );
936  rd_data( pls, &text.y, sizeof ( PLINT ) );
937  rd_data( pls, &text.refx, sizeof ( PLINT ) );
938  rd_data( pls, &text.refy, sizeof ( PLINT ) );
939 
940  rd_data( pls, &text.n_fci, sizeof ( PLUNICODE ) );
941  rd_data( pls, &text.n_char, sizeof ( PLUNICODE ) );
942  rd_data( pls, &text.n_ctrl_char, sizeof ( PLINT ) );
943 
944  rd_data( pls, &text.unicode_array_len, sizeof ( PLINT ) );
945 
946  if ( pls->dev_unicode )
947  {
948  plsfci( fci );
949  plP_esc( op, &text );
950  }
951 }
952 
953 //--------------------------------------------------------------------------
954 // plRemakePlot()
955 //
956 // Rebuilds plot from plot buffer, usually in response to a window
957 // resize or exposure event.
958 //--------------------------------------------------------------------------
959 
960 void
962 {
963  U_CHAR c;
964  int plbuf_status;
965  PLStream *save_pls;
966 
967  dbug_enter( "plRemakePlot" );
968 
969  // Change the status of the flags before checking for a buffer.
970  // Actually, more thought is needed if we want to support multithreaded
971  // code correctly, specifically the case where two threads are using
972  // the same plot stream (e.g. one thread is drawing the plot and another
973  // thread is processing window manager messages).
974  //
975  plbuf_status = pls->plbuf_write;
976  pls->plbuf_write = FALSE;
977  pls->plbuf_read = TRUE;
978 
979 #ifdef BUFFERED_FILE
980  if ( pls->plbufFile )
981  {
982  rewind( pls->plbufFile );
983 #else
984  if ( pls->plbuf_buffer )
985  {
986  pls->plbuf_readpos = 0;
987 #endif
988  // Need to change where plsc points to before processing the commands.
989  // If we have multiple plot streams, this will prevent the commands from
990  // going to the wrong plot stream.
991  //
992  save_pls = plsc;
993  plsc = pls;
994 
995  while ( rd_command( pls, &c ) )
996  {
997  plbuf_control( pls, c );
998  }
999 
1000  plsc = save_pls;
1001  }
1002 
1003  pls->plbuf_read = FALSE;
1004  pls->plbuf_write = plbuf_status;
1005 }
1006 
1007 //--------------------------------------------------------------------------
1008 // plbuf_control()
1009 //
1010 // Processes commands read from the plot buffer.
1011 //--------------------------------------------------------------------------
1012 
1013 static void
1015 {
1016  static U_CHAR c_old = 0;
1017 
1018  dbug_enter( "plbuf_control" );
1019 
1020  switch ( (int) c )
1021  {
1022  case INITIALIZE:
1023  rdbuf_init( pls );
1024  break;
1025 
1026  case EOP:
1027  rdbuf_eop( pls );
1028  break;
1029 
1030  case BOP:
1031  rdbuf_bop( pls );
1032  break;
1033 
1034  case CHANGE_STATE:
1035  rdbuf_state( pls );
1036  break;
1037 
1038  case LINE:
1039  rdbuf_line( pls );
1040  break;
1041 
1042  case POLYLINE:
1043  rdbuf_polyline( pls );
1044  break;
1045 
1046  case ESCAPE:
1047  rdbuf_esc( pls );
1048  break;
1049 
1050  default:
1051  pldebug( "plbuf_control", "Unrecognized command %d, previous %d\n", c, c_old );
1052  }
1053  c_old = c;
1054 }
1055 
1056 //--------------------------------------------------------------------------
1057 // rd_command()
1058 //
1059 // Read & return the next command
1060 //--------------------------------------------------------------------------
1061 
1062 static int
1064 {
1065  int count;
1066 
1067 #ifdef BUFFERED_FILE
1068  count = fread( p_c, sizeof ( U_CHAR ), 1, pls->plbufFile );
1069 #else
1070  if ( pls->plbuf_readpos < pls->plbuf_top )
1071  {
1072  *p_c = *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos );
1073  pls->plbuf_readpos += sizeof ( U_CHAR );
1074  count = sizeof ( U_CHAR );
1075  }
1076  else
1077  {
1078  count = 0;
1079  }
1080 #endif
1081  return ( count );
1082 }
1083 
1084 //--------------------------------------------------------------------------
1085 // rd_data()
1086 //
1087 // Read the data associated with the command
1088 //--------------------------------------------------------------------------
1089 
1090 static void
1091 rd_data( PLStream *pls, void *buf, size_t buf_size )
1092 {
1093 #ifdef BUFFERED_FILE
1094  plio_fread( buf, buf_size, 1, pls->plbufFile );
1095 #else
1096 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
1097 // then this code will have problems. A better approach might be to use
1098 // uint8_t from <stdint.h> but I do not know how portable that approach is
1099 //
1100  memcpy( buf, (U_CHAR *) pls->plbuf_buffer + pls->plbuf_readpos, buf_size );
1101  pls->plbuf_readpos += buf_size;
1102 #endif
1103 }
1104 
1105 //--------------------------------------------------------------------------
1106 // wr_command()
1107 //
1108 // Write the next command
1109 //--------------------------------------------------------------------------
1110 
1111 static void
1113 {
1114 #ifdef BUFFERED_FILE
1115  plio_fwrite( &c1, sizeof ( U_CHAR ), 1, pls->plbufFile );
1116 #else
1117  if ( ( pls->plbuf_top + sizeof ( U_CHAR ) ) >= pls->plbuf_buffer_size )
1118  {
1119  // Not enough space, need to grow the buffer
1120  pls->plbuf_buffer_size += pls->plbuf_buffer_grow;
1121 
1122  if ( pls->verbose )
1123  printf( "Growing buffer to %d KB\n", (int) ( pls->plbuf_buffer_size / 1024 ) );
1124  if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
1125  plexit( "plbuf wr_data: Plot buffer grow failed" );
1126  }
1127 
1128  *(U_CHAR *) ( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top ) = c;
1129  pls->plbuf_top += sizeof ( U_CHAR );
1130 #endif
1131 }
1132 
1133 //--------------------------------------------------------------------------
1134 // wr_data()
1135 //
1136 // Write the data associated with a command
1137 //--------------------------------------------------------------------------
1138 
1139 static void
1140 wr_data( PLStream *pls, void *buf, size_t buf_size )
1141 {
1142 #ifdef BUFFERED_FILE
1143  plio_fwrite( buf, buf_size, 1, pls->plbufFile );
1144 #else
1145  if ( ( pls->plbuf_top + buf_size ) >= pls->plbuf_buffer_size )
1146  {
1147  // Not enough space, need to grow the buffer
1148  // Must make sure the increase is enough for this data
1149  pls->plbuf_buffer_size += pls->plbuf_buffer_grow *
1150  ( ( pls->plbuf_top + buf_size - pls->plbuf_buffer_size ) /
1151  pls->plbuf_buffer_grow + 1 );
1152  while ( pls->plbuf_top + buf_size >= pls->plbuf_buffer_size )
1153  ;
1154 
1155  if ( ( pls->plbuf_buffer = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size ) ) == NULL )
1156  plexit( "plbuf wr_data: Plot buffer grow failed" );
1157  }
1158 
1159 // If U_CHAR is not the same size as what memcpy() expects (typically 1 byte)
1160 // then this code will have problems. A better approach might be to use
1161 // uint8_t from <stdint.h> but I do not know how portable that approach is
1162 //
1163  memcpy( (U_CHAR *) pls->plbuf_buffer + pls->plbuf_top, buf, buf_size );
1164  pls->plbuf_top += buf_size;
1165 #endif
1166 }
1167 
1168 // plbuf_save(state)
1169 //
1170 // Saves the current state of the plot into a save buffer.
1171 // This code was originally in gcw.c and gcw-lib.c. The original
1172 // code used a temporary file for the plot buffer and memory
1173 // to perserve colormaps. That method does not offer a clean
1174 // break between using memory buffers and file buffers. This
1175 // function preserves the same functionality by returning a data
1176 // structure that saves the plot buffer and colormaps seperately.
1177 //
1178 // The caller passes an existing save buffer for reuse or NULL
1179 // to force the allocation of a new buffer. Since one malloc()
1180 // is used for everything, the entire save buffer can be freed
1181 // with one free() call.
1182 //
1183 //
1185 {
1189 };
1190 
1191 struct _state
1192 {
1193  size_t size; // Size of the save buffer
1194  int valid; // Flag to indicate a valid save state
1195 #ifdef BUFFERED_FILE
1196  FILE *plbufFile;
1197 #else
1200  size_t plbuf_top;
1202 #endif
1204 };
1205 
1206 void * plbuf_save( PLStream *pls, void *state )
1207 {
1208  size_t save_size;
1209  struct _state *plot_state = (struct _state *) state;
1210  PLINT i;
1211  U_CHAR *buf; // Assume that this is byte-sized
1212 
1213  if ( pls->plbuf_write )
1214  {
1215  pls->plbuf_write = FALSE;
1216  pls->plbuf_read = TRUE;
1217 
1218  // Determine the size of the buffer required to save everything. We
1219  // assume that there are only two colormaps, but have written the code
1220  // that more than two can be handled with minimal changes.
1221  //
1222  save_size = sizeof ( struct _state )
1223  + 2 * sizeof ( struct _color_map )
1224  + (size_t) ( pls->ncol0 ) * sizeof ( PLColor )
1225  + (size_t) ( pls->ncol1 ) * sizeof ( PLColor );
1226 
1227 #ifndef BUFFERED_FILE
1228  // Only copy as much of the plot buffer that is being used
1229  save_size += pls->plbuf_top;
1230 #endif
1231 
1232  // If a buffer exists, determine if we need to resize it
1233  if ( state != NULL )
1234  {
1235  // We have a save buffer, is it smaller than the current size requirement?
1236  if ( plot_state->size < save_size )
1237  {
1238  // Yes, reallocate a larger one
1239  if ( ( plot_state = (struct _state *) realloc( state, save_size ) ) == NULL )
1240  {
1241  // NOTE: If realloc fails, then plot_state ill be NULL.
1242  // This will leave the original buffer untouched, thus we
1243  // mark it as invalid and return it back to the caller.
1244  //
1245  plwarn( "plbuf: Unable to reallocate sufficient memory to save state" );
1246  plot_state->valid = 0;
1247 
1248  return state;
1249  }
1250  plot_state->size = save_size;
1251  }
1252  }
1253  else
1254  {
1255  // A buffer does not exist, so we need to allocate one
1256  if ( ( plot_state = (struct _state *) malloc( save_size ) ) == NULL )
1257  {
1258  plwarn( "plbuf: Unable to allocate sufficient memory to save state" );
1259 
1260  return NULL;
1261  }
1262  plot_state->size = save_size;
1263 
1264 #ifdef BUFFERED_FILE
1265  // Make sure the FILE pointer is NULL in order to preven bad things from happening...
1266  plot_state->plbufFile = NULL;
1267 #endif
1268  }
1269 
1270  // At this point we have an appropriately sized save buffer.
1271  // We need to invalidate the state of the save buffer, since it
1272  // will not be valid until after everything is copied. We use
1273  // this approach vice freeing the memory and returning a NULL pointer
1274  // in order to prevent allocating and freeing memory needlessly.
1275  //
1276  plot_state->valid = 0;
1277 
1278  // Point buf to the space after the struct _state
1279  buf = (U_CHAR *) ( plot_state + 1 );
1280 
1281 #ifdef BUFFERED_FILE
1282  // Remove the old tempfile, if it exists
1283  if ( plot_state->plbufFile != NULL )
1284  {
1285  fclose( plot_state->plbufFile );
1286  }
1287 
1288  // Copy the plot buffer to a tempfile
1289  if ( ( plot_state->plbufFile = pl_create_tempfile( NULL ) ) == NULL )
1290  {
1291  // Throw a warning since this might be a permissions problem
1292  // and we may not want to force an exit
1293  //
1294  plwarn( "plbuf: Unable to open temporary file to save state" );
1295  return (void *) plot_state;
1296  }
1297  else
1298  {
1299  U_CHAR tmp;
1300 
1301  rewind( pls->plbufFile );
1302  while ( count = fread( &tmp, sizeof ( U_CHAR ), 1, pls->plbufFile ) )
1303  {
1304  if ( fwrite( &tmp, sizeof ( U_CHAR ), 1, plot_state->plbufFile ) != count )
1305  {
1306  // Throw a warning since this might be a permissions problem
1307  // and we may not want to force an exit
1308  //
1309  plwarn( "plbuf: Unable to write to temporary file" );
1310  fclose( plot_state->plbufFile );
1311  plot_state->plbufFile = NULL;
1312  return (void *) plot_state;
1313  }
1314  }
1315  }
1316 #else
1317  // Again, note, that we only copy the portion of the plot buffer that is being used
1318  plot_state->plbuf_buffer_size = pls->plbuf_top;
1319  plot_state->plbuf_top = pls->plbuf_top;
1320  plot_state->plbuf_readpos = 0;
1321 
1322  // Create a pointer that points in the space we allocated after struct _state
1323  plot_state->plbuf_buffer = (void *) buf;
1324  buf += pls->plbuf_top;
1325 
1326  // Copy the plot buffer to our new buffer. Again, I must stress, that we only
1327  // are copying the portion of the plot buffer that is being used
1328  //
1329  if ( memcpy( plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL )
1330  {
1331  // This should never be NULL
1332  plwarn( "plbuf: Got a NULL in memcpy!" );
1333  return (void *) plot_state;
1334  }
1335 #endif
1336 
1337  pls->plbuf_write = TRUE;
1338  pls->plbuf_read = FALSE;
1339 
1340  // Save the colormaps. First create a pointer that points in the space we allocated
1341  // after the plot buffer
1342  plot_state->color_map = (struct _color_map *) buf;
1343  buf += sizeof ( struct _color_map ) * 2;
1344 
1345  // Then we need to make space for the colormaps themselves
1346  plot_state->color_map[0].cmap = (PLColor *) buf;
1347  buf += sizeof ( PLColor ) * (size_t) ( pls->ncol0 );
1348  plot_state->color_map[1].cmap = (PLColor *) buf;
1349  buf += sizeof ( PLColor ) * (size_t) ( pls->ncol1 );
1350 
1351  // Save cmap 0
1352  plot_state->color_map[0].icol = pls->icol0;
1353  plot_state->color_map[0].ncol = pls->ncol0;
1354  for ( i = 0; i < pls->ncol0; i++ )
1355  {
1356  pl_cpcolor( &( plot_state->color_map[0].cmap[i] ), &pls->cmap0[i] );
1357  }
1358 
1359  // Save cmap 1
1360  plot_state->color_map[1].icol = pls->icol1;
1361  plot_state->color_map[1].ncol = pls->ncol1;
1362  for ( i = 0; i < pls->ncol1; i++ )
1363  {
1364  pl_cpcolor( &( plot_state->color_map[1].cmap[i] ), &pls->cmap1[i] );
1365  }
1366 
1367  plot_state->valid = 1;
1368  return (void *) plot_state;
1369  }
1370 
1371  return NULL;
1372 }
1373 
1374 // plbuf_restore(PLStream *, state)
1375 //
1376 // Restores the passed state
1377 //
1378 void plbuf_restore( PLStream *pls, void *state )
1379 {
1380  struct _state *new_state = (struct _state *) state;
1381 
1382 #ifdef BUFFERED_FILE
1383  pls->plbufFile = new_state->save_file;
1384 #else
1385  pls->plbuf_buffer = new_state->plbuf_buffer;
1386  pls->plbuf_buffer_size = new_state->plbuf_buffer_size;
1387  pls->plbuf_top = new_state->plbuf_top;
1388  pls->plbuf_readpos = new_state->plbuf_readpos;
1389 #endif
1390  // cmap 0
1391  pls->cmap0 = new_state->color_map[0].cmap;
1392  pls->icol0 = new_state->color_map[0].icol;
1393  pls->ncol0 = new_state->color_map[0].ncol;
1394  // cmap 1
1395  pls->cmap1 = new_state->color_map[1].cmap;
1396  pls->icol1 = new_state->color_map[1].icol;
1397  pls->ncol1 = new_state->color_map[1].ncol;
1398 }
1399 
1400 // plbuf_switch(PLStream *, state)
1401 //
1402 // Makes the passed state the current one. Preserves the previous state
1403 // by returning a save buffer.
1404 //
1405 // NOTE: The current implementation can cause a memory leak under the
1406 // following scenario:
1407 // 1) plbuf_save() is called
1408 // 2) plbuf_switch() is called
1409 // 3) Commands are called which cause the plot buffer to grow
1410 // 4) plbuf_swtich() is called
1411 //
1412 void * plbuf_switch( PLStream *pls, void *state )
1413 {
1414  struct _state *new_state = (struct _state *) state;
1415  struct _state *prev_state;
1416  size_t save_size;
1417 
1418  // No saved state was passed, return a NULL--we hope the caller
1419  // is smart enough to notice
1420  //
1421  if ( state == NULL )
1422  return NULL;
1423 
1424  if ( !new_state->valid )
1425  {
1426  plwarn( "plbuf: Attempting to switch to an invalid saved state" );
1427  return NULL;
1428  }
1429 
1430  save_size = sizeof ( struct _state )
1431  + 2 * sizeof ( struct _color_map );
1432 
1433  if ( ( prev_state = (struct _state *) malloc( save_size ) ) == NULL )
1434  {
1435  plwarn( "plbuf: Unable to allocate memory to save state" );
1436  return NULL;
1437  }
1438 
1439  // Set some housekeeping variables
1440  prev_state->size = save_size;
1441  prev_state->valid = 1;
1442 
1443  // Preserve the existing state
1444 #ifdef BUFFERED_FILE
1445  prev_state->plbufFile = pls->plbufFile;
1446 #else
1447  prev_state->plbuf_buffer = pls->plbuf_buffer;
1448  prev_state->plbuf_buffer_size = pls->plbuf_buffer_size;
1449  prev_state->plbuf_top = pls->plbuf_top;
1450  prev_state->plbuf_readpos = pls->plbuf_readpos;
1451 #endif
1452  // cmap 0
1453  prev_state->color_map[0].cmap = pls->cmap0;
1454  prev_state->color_map[0].icol = pls->icol0;
1455  prev_state->color_map[0].ncol = pls->ncol0;
1456  // cmap 1
1457  prev_state->color_map[1].cmap = pls->cmap1;
1458  prev_state->color_map[1].icol = pls->icol1;
1459  prev_state->color_map[1].ncol = pls->ncol1;
1460 
1461  plbuf_restore( pls, new_state );
1462 
1463  return (void *) prev_state;
1464 }
1465 
1466