PLplot: plbuf.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
65 plbuf_init( PLStream *pls )
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
129 plbuf_eop( PLStream * PL_UNUSED( pls ) )
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
146 plbuf_bop( PLStream *pls )
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
166 pls->plbuf_buffer_size = pls->plbuf_buffer_grow;
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
189 plbuf_tidy( PLStream * PL_UNUSED( pls ) )
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
209 plbuf_state( PLStream *pls, PLINT op )
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
280 plbuf_text( PLStream *pls, EscText *text )
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
320 plbuf_text_unicode( PLStream *pls, EscText *text )
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:
405 case PLESC_START_RASTERIZE:
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
419 plbuf_fill( PLStream *pls )
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
459 rdbuf_init( PLStream * PL_UNUSED( pls ) )
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
471 rdbuf_line( PLStream *pls )
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
491 rdbuf_polyline( PLStream *pls )
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
537 rdbuf_eop( PLStream * PL_UNUSED( pls ) )
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
549 rdbuf_bop( PLStream *pls )
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
563 rdbuf_state( PLStream *pls )
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;
578 plP_state( PLSTATE_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
616 plP_state( PLSTATE_COLOR0 );
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
631 plP_state( PLSTATE_COLOR1 );
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;
641 plP_state( PLSTATE_FILL );
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
680 rdbuf_esc( PLStream *pls )
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;
711 case PLESC_START_RASTERIZE:
712 plP_esc( PLESC_START_RASTERIZE, NULL );
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
727 rdbuf_fill( PLStream *pls )
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
772 rdbuf_image( PLStream *pls )
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
833 rdbuf_swin( PLStream *pls )
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
857 rdbuf_text( PLStream *pls )
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
914 rdbuf_text_unicode( PLINT op, PLStream *pls )
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
963 plRemakePlot( PLStream *pls )
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
1016 plbuf_control( PLStream *pls, U_CHAR c )
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
1065 rd_command( PLStream *pls, U_CHAR *p_c )
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
1114 wr_command( PLStream *pls, U_CHAR c )
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 //
1186 struct _color_map
1187 {
1188 PLColor *cmap;
1189 PLINT icol;
1190 PLINT ncol;
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
1200 void *plbuf_buffer;
1201 size_t plbuf_buffer_size;
1202 size_t plbuf_top;
1203 size_t plbuf_readpos;
1204 #endif
1205 struct _color_map *color_map;
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