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