1 // Copyright 1991, 1992, 1993, 1994, 1995
2 // Geoffrey Furnish furnish@dino.ph.utexas.edu
3 // Maurice LeBrun mjl@dino.ph.utexas.edu
4 // Institute for Fusion Studies University of Texas at Austin
5 //
6 // Copyright (C) 2004-2015 Alan W. Irwin
7 // Copyright (C) 2004 Maurice LeBrun
8 // Copyright (C) 2004 Andrew Ross
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 //--------------------------------------------------------------------------
28 //
29 // This file contains the code to render a PLplot metafile, written by
30 // the metafile driver, plmeta.c.
31 //
32
33 #define DEBUG
34 #define DEBUG_ENTER
35
36 #define NEED_PLDEBUG
37 #include "plplotP.h"
38 #include "plevent.h"
39 #include "metadefs.h"
40 #include <ctype.h>
41
42 // Static function prototypes.
43 // These handle the command loop
44
45 static void process_next( U_CHAR c );
46 static void plr_init( U_CHAR c );
47 static void plr_line( U_CHAR c );
48 static void plr_eop( U_CHAR c );
49 static void plr_eop1( U_CHAR c );
50 static void plr_bop( U_CHAR c );
51 static void plr_state( U_CHAR c );
52 static void plr_esc( U_CHAR c );
53 static void plresc_fill( void );
54 static void plresc_rgb( void );
55 static void plresc_ancol( void );
56
57 // Support functions
58
59 static U_CHAR getcommand( void );
60 static void ungetcommand( U_CHAR );
61 static void get_ncoords( PLFLT *x, PLFLT *y, PLINT n );
62 static void plr_exit( char *errormsg );
63 static void NextFamilyFile( U_CHAR * );
64 static void PrevFamilyFile( void );
65 static void ReadPageHeader( void );
66 static void plr_KeyEH( PLGraphicsIn *, void *, int * );
67 static void SeekToDisp( long );
68 static void SeekOnePage( void );
69 static void SeekToNextPage( void );
70 static void SeekToCurPage( void );
71 static void SeekToPrevPage( void );
72 static void SeekTo( FPOS_T );
73 static void doseek( FPOS_T );
74 static void PageIncr( void );
75 static void PageDecr( void );
76
77 // Initialization functions
78
79 static void Init( int, char ** );
80 static int ProcessFile( int, char ** );
81 static int OpenMetaFile( char ** );
82 static int ReadFileHeader( void );
83
84 // Option handlers
85
86 static int Opt_v( const char *, const char *, void * );
87 static int Opt_i( const char *, const char *, void * );
88 static int Opt_b( const char *, const char *, void * );
89 static int Opt_e( const char *, const char *, void * );
90 static int Opt_p( const char *, const char *, void * );
91
92 // Global variables
93
94 // Copies of argc, argv, for use with multiple files
95
96 static int myargc;
97 static char **myargv;
98
99 // Page info
100
101 static PLINT disp_beg = 1; // Where to start plotting
102 static PLINT disp_end = -1; // Where to stop (0 to disable)
103 static PLINT curdisp; // Current page number
104 static PLINT cursub; // Current subpage
105 static PLINT curpage; // Current plot number
106 static PLINT nsubx; // subpages in x
107 static PLINT nsuby; // subpages in y
108 static PLINT target_disp; // Page we are seeking to
109 static PLINT target_page; // Plot we are seeking to
110 static PLINT delta; // Number of pages to go forward/back
111 static PLINT pages; // Number of pages in file
112
113 static int no_pagelinks; // Set if metafile doesn't have page links
114 static int end_of_page; // Set when we're at the end of a page
115 static int seek_mode; // Set after a seek, before a BOP
116 static int addeof_beg; // Set when we are counting back from eof
117 static int addeof_end; // Set when we are counting back from eof
118 static int first_page; // Set when we're on the first page in the file
119
120 static FPOS_T prevpage_loc; // Byte position of previous page header
121 static FPOS_T curpage_loc; // Byte position of current page header
122 static FPOS_T nextpage_loc; // Byte position of next page header
123
124 // File info
125
126 static int input_type; // 0 for file, 1 for stream
127 static int isfile; // shorthand -- set if file
128 static int do_file_loop = 1; // loop over multiple files if set
129 static PDFstrm *pdfs; // PDF stream handle
130 static FILE *MetaFile; // Actual metafile handle, for seeks etc
131
132 static char BaseName[80] = "", FileName[90] = "";
133 static PLINT is_family, member = 1;
134 static char mf_magic[40], mf_version[40];
135
136 // Dummy vars for reading stuff that is to be thrown away
137
138 static U_CHAR dum_uchar;
139 static U_SHORT dum_ushort;
140 static float dum_float;
141
142 // Plot dimensions
143
144 static short xmin = 0;
145 static short xmax = PLMETA_X_OLD;
146 static short ymin = 0;
147 static short ymax = PLMETA_Y_OLD;
148 static PLINT xlen, ylen;
149
150 static float pxlx = PIXEL_RES_X_OLD;
151 static float pxly = PIXEL_RES_Y_OLD;
152
153 static PLFLT dev_xpmm, dev_ypmm;
154 static PLINT dev_xmin, dev_xmax, dev_ymin, dev_ymax, dev_xlen, dev_ylen;
155 static PLFLT vpxmin, vpxmax, vpxlen, vpymin, vpymax, vpylen;
156
157 // Geometry info
158
159 static float xdpi, ydpi;
160 static PLINT xlength, ylength, xoffset, yoffset;
161
162 // Miscellaneous
163
164 static U_CHAR c_old, c1;
165 static U_SHORT npts;
166 static int direction_flag, isanum, at_eop;
167 static char num_buffer[20];
168 static PLFLT x[PL_MAXPOLY], y[PL_MAXPOLY];
169 static char buffer[256];
170 static char * cmdstring[256];
171
172 // Exit codes
173
174 #define EX_SUCCESS 0 // success!
175 #define EX_ARGSBAD 1 // invalid args
176 #define EX_BADFILE 2 // invalid filename or contents
177
178 // A little function to help with debugging
179
180 #ifdef DEBUG
181 #define DEBUG_PRINT_LOCATION( a ) PrintLocation( a )
182
PrintLocation(char * tag)183 static void PrintLocation( char *tag )
184 {
185 if ( isfile )
186 {
187 FPOS_T current_offset;
188
189 if ( pl_fgetpos( MetaFile, ¤t_offset ) )
190 plexit( "PrintLocation (plrender.c): fgetpos call failed" );
191
192 pldebug( tag, "at offset %d in file %s\n",
193 (int) current_offset, FileName );
194 }
195 }
196 #else
197 #define DEBUG_PRINT_LOCATION( a )
198 #endif
199
200 //--------------------------------------------------------------------------
201 // Options data structure definition.
202 //--------------------------------------------------------------------------
203
204 static PLOptionTable options[] = {
205 {
206 "v", // Version
207 Opt_v,
208 NULL,
209 NULL,
210 PL_OPT_FUNC | PL_OPT_NODELETE,
211 "-v",
212 "Print out the plrender version number"
213 },
214 {
215 "i", // Input file
216 Opt_i,
217 NULL,
218 NULL,
219 PL_OPT_FUNC | PL_OPT_ARG,
220 "-i name",
221 "Input filename"
222 },
223 {
224 "b", // Beginning page number
225 Opt_b,
226 NULL,
227 NULL,
228 PL_OPT_FUNC | PL_OPT_ARG,
229 "-b number",
230 "Beginning page number"
231 },
232 {
233 "e", // End page number
234 Opt_e,
235 NULL,
236 NULL,
237 PL_OPT_FUNC | PL_OPT_ARG,
238 "-e number",
239 "End page number"
240 },
241 {
242 "p", // Specified page only
243 Opt_p,
244 NULL,
245 NULL,
246 PL_OPT_FUNC | PL_OPT_ARG,
247 "-p page",
248 "Plot given page only"
249 },
250 {
251 NULL, // option
252 NULL, // handler
253 NULL, // client data
254 NULL, // address of variable to set
255 0, // mode flag
256 NULL, // short syntax
257 NULL
258 } // long syntax
259 };
260
261 static const char *notes[] = {
262 "If the \"-i\" flag is omitted, unrecognized input will assumed to be filename",
263 "parameters. Specifying \"-\" for the input or output filename means use stdin",
264 "or stdout, respectively. See the manual for more detail.",
265 NULL
266 };
267
268 //--------------------------------------------------------------------------
269 // main()
270 //
271 // plrender -- render a series of PLplot metafiles.
272 //--------------------------------------------------------------------------
273
274 int
main(int argc,char * argv[])275 main( int argc, char *argv[] )
276 {
277 Init( argc, argv );
278
279 // Process first file. There must be at least one.
280
281 if ( ProcessFile( argc, argv ) )
282 {
283 fprintf( stderr, "\nNo filename specified.\n" );
284 plOptUsage();
285 exit( EX_ARGSBAD );
286 }
287
288 // Process any additional files
289
290 if ( do_file_loop )
291 {
292 pltext();
293 while ( !ProcessFile( argc, argv ) )
294 ;
295 }
296 plend();
297 if ( myargv )
298 free( myargv );
299 exit( EX_SUCCESS );
300 }
301
302 //--------------------------------------------------------------------------
303 // Init()
304 //
305 // Do initialization for main().
306 //--------------------------------------------------------------------------
307
308 static void
Init(int argc,char ** argv)309 Init( int argc, char **argv )
310 {
311 int i;
312
313 dbug_enter( "Init" );
314
315 // Set up for argv processing
316
317 plSetUsage( "plrender", "\nUsage:\n plrender [options] [files]\n" );
318
319 plMergeOpts( options, "plrender options", notes );
320
321 // Save argv list for future reuse
322
323 myargv = (char **) malloc( argc * sizeof ( char * ) );
324 myargc = argc;
325 for ( i = 0; i < argc; i++ )
326 {
327 myargv[i] = argv[i];
328 }
329
330 // Set up names for commands for debugging
331
332 for ( i = 0; i < 256; i++ )
333 cmdstring[i] = "UNDEFINED";
334
335 cmdstring[INITIALIZE] = "INITIALIZE";
336 cmdstring[CLOSE] = "CLOSE";
337 cmdstring[SWITCH_TO_TEXT] = "SWITCH_TO_TEXT";
338 cmdstring[SWITCH_TO_GRAPH] = "SWITCH_TO_GRAPH";
339 cmdstring[EOP] = "EOP";
340 cmdstring[BOP] = "BOP";
341 cmdstring[NEW_COLOR] = "NEW_COLOR";
342 cmdstring[NEW_WIDTH] = "NEW_WIDTH";
343 cmdstring[LINE] = "LINE";
344 cmdstring[LINETO] = "LINETO";
345 cmdstring[ESCAPE] = "ESCAPE";
346 cmdstring[ADVANCE] = "ADVANCE";
347 cmdstring[POLYLINE] = "POLYLINE";
348 cmdstring[NEW_COLOR0] = "NEW_COLOR0";
349 cmdstring[NEW_COLOR1] = "NEW_COLOR1";
350 cmdstring[CHANGE_STATE] = "CHANGE_STATE";
351 cmdstring[BOP0] = "BOP0";
352 cmdstring[END_OF_FIELD] = "END_OF_FIELD";
353 }
354
355 //--------------------------------------------------------------------------
356 // ProcessFile()
357 //
358 // Renders a file, using given command flags.
359 //--------------------------------------------------------------------------
360
361 static int
ProcessFile(int argc,char ** argv)362 ProcessFile( int argc, char **argv )
363 {
364 int i;
365 U_CHAR c = 0;
366 char devname[80];
367
368 dbug_enter( "ProcessFile" );
369
370 // Do all rendering in a new plot stream to make cleanup easier.
371
372 plsstrm( 1 );
373
374 // Process plrender and PLplot (internal) command line options
375 // Since we aren't using full parsing, plparseopts() will stop when it hits
376 // a non-flag item
377
378 if ( plparseopts( &argc, argv, 0 ) )
379 exit( 1 );
380
381 // Any remaining flags are illegal.
382
383 if ( argv[1] != NULL && ( argv )[1][0] == '-' )
384 {
385 fprintf( stderr, "\nBad command line option \"%s\"\n", argv[1] );
386 plOptUsage();
387 exit( 1 );
388 }
389
390 // Try to open metafile.
391
392 if ( OpenMetaFile( argv ) )
393 return 1;
394
395 // Initialize file and read header
396
397 pdfs = pdf_finit( MetaFile );
398
399 if ( ReadFileHeader() )
400 exit( EX_BADFILE );
401
402 // Read & process any state info before the INITIALIZE
403
404 for (;; )
405 {
406 c_old = c;
407 c = getcommand();
408
409 if ( c == INITIALIZE )
410 {
411 ungetcommand( c );
412 break;
413 }
414 process_next( c );
415 }
416
417 //
418 // Reprocess the command line options so that they supercede their possible
419 // counterparts in the metafile header.
420 //
421
422 argc = myargc;
423 for ( i = 0; i < argc; i++ )
424 {
425 argv[i] = myargv[i];
426 }
427 plparseopts( &argc, argv, 0 );
428
429 // Miscellaneous housekeeping
430
431 if ( addeof_beg )
432 disp_beg += pages;
433 if ( addeof_end )
434 disp_end += pages;
435
436 plgdev( devname );
437 if ( strncmp( devname, "tk", 2 ) == 0 )
438 {
439 plsetopt( "-drvopt", "tcl_cmd=set plw_create_proc plr_create" );
440 }
441
442 //
443 // Read & process metafile commands.
444 // If familying is turned on, the end of one member file is just treated as
445 // a page break assuming the next member file exists.
446 //
447
448 for (;; )
449 {
450 c_old = c;
451 c = getcommand();
452
453 if ( c == CLOSE )
454 {
455 if ( is_family )
456 NextFamilyFile( &c );
457 if ( !is_family )
458 break;
459 }
460
461 if ( ( c == BOP || c == BOP0 || c == ADVANCE ) && curdisp == disp_end )
462 break;
463
464 process_next( c );
465 }
466
467 // Finish up
468
469 pdf_close( pdfs );
470 *FileName = '\0';
471
472 // A hack for old metafiles
473
474 if ( strcmp( mf_version, "1993a" ) >= 0 )
475 plspause( 0 );
476
477 plend1();
478
479 // Restore the old argc/argv
480
481 argc = myargc;
482 for ( i = 0; i < argc; i++ )
483 {
484 argv[i] = myargv[i];
485 }
486
487 return 0;
488 }
489
490 //--------------------------------------------------------------------------
491 // OpenMetaFile()
492 //
493 // Attempts to open a metafile. If the output file isn't already determined
494 // via the -i or -f flags, we assume it's the second argument in argv[] (the
495 // first should still hold the program name). Null out the string after
496 // copying it so that it doesn't appear on subsequent passes of the command
497 // line.
498 //--------------------------------------------------------------------------
499
500 static int
OpenMetaFile(char ** argv)501 OpenMetaFile( char **argv )
502 {
503 char name[70];
504
505 dbug_enter( "OpenMetaFile" );
506
507 if ( !strcmp( FileName, "-" ) )
508 input_type = 1;
509
510 isfile = ( input_type == 0 );
511
512 if ( !isfile )
513 {
514 MetaFile = stdin;
515 do_file_loop = 0;
516 }
517 else
518 {
519 if ( *FileName == '\0' )
520 {
521 if ( argv[1] != NULL && *argv[1] != '\0' )
522 {
523 strncpy( FileName, argv[1], sizeof ( FileName ) - 1 );
524 FileName[sizeof ( FileName ) - 1] = '\0';
525 argv[1][0] = '\0';
526 }
527 else
528 {
529 return 1;
530 }
531 }
532
533 // Try to read named Metafile. The following cases are checked in order:
534 // <FileName>
535 // <FileName>.1
536 // <FileName>.plm
537 // <FileName>.plm.1
538 //
539 pldebug( "OpenMetaFile", "Trying to open metafile %s.\n", FileName );
540 strncpy( name, FileName, sizeof ( name ) - 1 );
541 name[sizeof ( name ) - 1] = '\0';
542
543 if ( ( MetaFile = fopen( FileName, "rb" ) ) != NULL )
544 {
545 return 0;
546 }
547
548 (void) sprintf( FileName, "%s.%i", name, (int) member );
549 if ( ( MetaFile = fopen( FileName, "rb" ) ) != NULL )
550 {
551 (void) sprintf( BaseName, "%s", name );
552 is_family = 1;
553 return 0;
554 }
555
556 (void) sprintf( FileName, "%s.plm", name );
557 if ( ( MetaFile = fopen( FileName, "rb" ) ) != NULL )
558 {
559 return 0;
560 }
561
562 (void) sprintf( FileName, "%s.plm.%i", name, (int) member );
563 if ( ( MetaFile = fopen( FileName, "rb" ) ) != NULL )
564 {
565 (void) sprintf( BaseName, "%s.plm", name );
566 is_family = 1;
567 return 0;
568 }
569
570 fprintf( stderr, "\nUnable to open: %s.\n", name );
571 plOptUsage();
572 exit( EX_BADFILE );
573 }
574
575 return 0;
576 }
577
578 //--------------------------------------------------------------------------
579 // Process the command loop
580 //--------------------------------------------------------------------------
581
582 //--------------------------------------------------------------------------
583 // process_next()
584 //
585 // Process a command.
586 // Typically plrender issues commands to PLplot much like an application
587 // program would. This results in a more robust and flexible API. On the
588 // other hand, it is sometimes necessary to directly call low-level PLplot
589 // routines to achieve certain special effects, increase performance, or
590 // simplify the code.
591 //--------------------------------------------------------------------------
592
593 static void
process_next(U_CHAR c)594 process_next( U_CHAR c )
595 {
596 // Specially handle line draws to contain output when debugging
597
598 switch ( (int) c )
599 {
600 case LINE:
601 case LINETO:
602 case POLYLINE:
603 plr_line( c );
604 if ( c != c_old )
605 pldebug( "process_next", "processing command %s\n", cmdstring[c] );
606 return;
607 }
608
609 // Everything else
610
611 pldebug( "process_next", "processing command %s\n", cmdstring[c] );
612
613 switch ( (int) c )
614 {
615 case INITIALIZE:
616 plr_init( c );
617 return;
618
619 case EOP:
620 plr_eop( c );
621 return;
622
623 case BOP:
624 case BOP0:
625 plr_bop( c );
626 return;
627
628 case CHANGE_STATE:
629 plr_state( getcommand() );
630 return;
631
632 case ESCAPE:
633 plr_esc( c );
634 return;
635
636 // These are all commands that should be absent from current metafiles but
637 // are recognized here for backward compatibility with old metafiles
638
639 case ADVANCE:
640 // Note here we use plr_eop1() to avoid multiple ungetc's
641 plr_eop1( c );
642 plr_bop( c );
643 return;
644
645 case NEW_WIDTH:
646 plr_state( PLSTATE_WIDTH );
647 return;
648
649 case NEW_COLOR0:
650 plr_state( PLSTATE_COLOR0 );
651 return;
652
653 case NEW_COLOR1:
654 plr_state( PLSTATE_COLOR1 );
655 return;
656
657 case SWITCH_TO_TEXT:
658 case SWITCH_TO_GRAPH:
659 return;
660
661 default:
662 sprintf( buffer, "process_next: Unrecognized command code %d", (int) c );
663 plr_exit( buffer );
664 }
665 }
666
667 //--------------------------------------------------------------------------
668 // void plr_init()
669 //
670 // Handle initialization.
671 //--------------------------------------------------------------------------
672
673 static void
plr_init(U_CHAR c)674 plr_init( U_CHAR c )
675 {
676 int debug = 0;
677 PLFLT aspect, dev_aspect, ratio;
678
679 dbug_enter( "plr_init" );
680
681 // Register event handler
682
683 plsKeyEH( plr_KeyEH, NULL );
684
685 // Note: many drivers ignore these, needed to preserve the aspect ratio
686
687 plspage( xdpi, ydpi, xlength, ylength, xoffset, yoffset );
688
689 // Start up PLplot
690
691 plinit();
692 plP_gsub( &nsubx, &nsuby, &cursub );
693
694 // Set aspect ratio to the natural ratio of the metafile coordinate system.
695
696 xlen = xmax - xmin;
697 ylen = ymax - ymin;
698
699 aspect = ( ylen / pxly ) / ( xlen / pxlx );
700
701 if ( debug )
702 printf( "xlen %d pxlx %f ylen %d pxly %f\n",
703 xlen, pxlx, ylen, pxly );
704
705 // Aspect ratio of output device
706
707 plP_gphy( &dev_xmin, &dev_xmax, &dev_ymin, &dev_ymax );
708 plP_gpixmm( &dev_xpmm, &dev_ypmm );
709
710 dev_xlen = dev_xmax - dev_xmin;
711 dev_ylen = dev_ymax - dev_ymin;
712
713 if ( debug )
714 printf( "dev_xlen %d dev_xpmm %f dev_ylen %d dev_ypmm %f\n",
715 dev_xlen, dev_xpmm, dev_ylen, dev_ypmm );
716
717 dev_aspect = ( dev_ylen / dev_ypmm ) / ( dev_xlen / dev_xpmm );
718
719 if ( dev_aspect <= 0. )
720 fprintf( stderr, "Aspect ratio error: dev_aspect = %f\n", dev_aspect );
721
722 ratio = aspect / dev_aspect;
723
724 if ( debug )
725 printf( "ratio %f aspect %f dev_aspect %f\n",
726 ratio, aspect, dev_aspect );
727
728 // Default relative coordinate space
729
730 vpxlen = 1.0;
731 vpylen = 1.0;
732 vpxmin = 0.5 - vpxlen / 2.;
733 vpymin = 0.5 - vpylen / 2.;
734 vpxmax = vpxmin + vpxlen;
735 vpymax = vpymin + vpylen;
736
737 //
738 // Construct viewport that preserves the aspect ratio of the original device
739 // (plmeta output file). Thus you automatically get all physical coordinate
740 // plots to come out correctly. Note: this could also be done using the
741 // driver interface function plsdimap.
742 //
743
744 if ( ratio <= 0 )
745 fprintf( stderr, "Aspect ratio error: ratio = %f\n", ratio );
746 else if ( ratio < 1 )
747 vpylen = ratio;
748 else
749 vpxlen = 1. / ratio;
750
751 vpxmin = ( 1. - vpxlen ) / 2.;
752 vpxmax = vpxmin + vpxlen;
753
754 vpymin = ( 1. - vpylen ) / 2.;
755 vpymax = vpymin + vpylen;
756
757 if ( debug )
758 printf( "vpxmin %f vpxmax %f vpymin %f vpymax %f\n",
759 vpxmin, vpxmax, vpymin, vpymax );
760
761 // Seek to first page
762
763 cursub = nsubx * nsuby;
764 if ( disp_beg > 1 )
765 {
766 if ( no_pagelinks )
767 plwarn( "plrender: Metafile does not support page seeks" );
768 else
769 {
770 ReadPageHeader();
771 SeekToDisp( disp_beg );
772 }
773 }
774 }
775
776 //--------------------------------------------------------------------------
777 // plr_line()
778 //
779 // Draw a line or polyline.
780 // Multiple connected lines (i.e. LINETO's) are collapsed into a polyline.
781 //--------------------------------------------------------------------------
782
783 static void
plr_line(U_CHAR c)784 plr_line( U_CHAR c )
785 {
786 npts = 1;
787
788 switch ( (int) c )
789 {
790 case LINE:
791 get_ncoords( x, y, 1 );
792
793 case LINETO:
794 for (;; )
795 {
796 get_ncoords( x + npts, y + npts, 1 );
797
798 npts++;
799 if ( npts == PL_MAXPOLY )
800 break;
801
802 c1 = getcommand();
803 if ( c1 != LINETO )
804 {
805 ungetcommand( c1 );
806 break;
807 }
808 }
809 break;
810
811 case POLYLINE:
812 plm_rd( pdf_rd_2bytes( pdfs, &npts ) );
813 get_ncoords( x, y, npts );
814 break;
815 }
816
817 plline( npts, x, y );
818
819 x[0] = x[npts - 1];
820 y[0] = y[npts - 1];
821 }
822
823 //--------------------------------------------------------------------------
824 // get_ncoords()
825 //
826 // Read n coordinate vectors.
827 //--------------------------------------------------------------------------
828
829 #define plr_rdn( code ) \
830 if ( code ) { fprintf( stderr, \
831 "Unable to read in %s at line %d, bytecount %d\n\
832 Bytes requested: %d\n", __FILE__, __LINE__, \
833 (int) pdfs->bp, (int) 2 * n ); return; }
834
835 static void
get_ncoords(PLFLT * x,PLFLT * y,PLINT n)836 get_ncoords( PLFLT *x, PLFLT *y, PLINT n )
837 {
838 PLINT i;
839 short _xs[PL_MAXPOLY], _ys[PL_MAXPOLY];
840 short *xs, *ys;
841
842 if ( n > PL_MAXPOLY )
843 {
844 xs = (short *) malloc( sizeof ( short ) * n );
845 ys = (short *) malloc( sizeof ( short ) * n );
846 }
847 else
848 {
849 xs = _xs;
850 ys = _ys;
851 }
852
853 plr_rdn( pdf_rd_2nbytes( pdfs, (U_SHORT *) xs, n ) );
854 plr_rdn( pdf_rd_2nbytes( pdfs, (U_SHORT *) ys, n ) );
855
856 for ( i = 0; i < n; i++ )
857 {
858 x[i] = xs[i];
859 y[i] = ys[i];
860 }
861
862 if ( n > PL_MAXPOLY )
863 {
864 free( xs );
865 free( ys );
866 }
867
868 return;
869 }
870
871 //--------------------------------------------------------------------------
872 // plr_eop()
873 //
874 // Handle end of page.
875 //
876 // Here we run into a bit of difficulty with packed pages -- at the end
877 // there is no EOP operation done if the page is only partially full.
878 // So I peek ahead to see if the next operation is a CLOSE, and if so,
879 // push back the CLOSE and issue an EOP regardless.
880 //--------------------------------------------------------------------------
881
882 static void
plr_eop(U_CHAR c)883 plr_eop( U_CHAR c )
884 {
885 dbug_enter( "plr_eop" );
886
887 c1 = getcommand();
888 ungetcommand( c1 );
889 if ( c1 == CLOSE )
890 end_of_page = 1;
891
892 plr_eop1( c );
893 }
894
895 //--------------------------------------------------------------------------
896 // plr_eop1()
897 //
898 // Handle end of page.
899 //
900 // This is for use with page advances where plr_eop's packed-page logic isn't
901 // needed and in fact results in back-to-back ungetc's which are not
902 // guaranteed to work.
903 //--------------------------------------------------------------------------
904
905 static void
plr_eop1(U_CHAR c)906 plr_eop1( U_CHAR c )
907 {
908 dbug_enter( "plr_eop1" );
909
910 if ( cursub == nsubx * nsuby )
911 end_of_page = 1;
912
913 if ( end_of_page == 1 )
914 {
915 at_eop = 1;
916 plP_eop();
917 at_eop = 0;
918 }
919 }
920
921 //--------------------------------------------------------------------------
922 // plr_bop()
923 //
924 // Page/subpage advancement.
925 //--------------------------------------------------------------------------
926
927 static void
plr_bop(U_CHAR c)928 plr_bop( U_CHAR c )
929 {
930 dbug_enter( "plr_bop" );
931
932 ungetcommand( c );
933 ReadPageHeader();
934
935 // Advance and setup the page or subpage
936
937 if ( end_of_page )
938 {
939 plP_bop();
940 end_of_page = 0;
941 seek_mode = 0;
942 }
943
944 plP_ssub( nsubx, nsuby, cursub );
945 plP_setsub();
946
947 plvpor( vpxmin, vpxmax, vpymin, vpymax );
948 plwind( (PLFLT) xmin, (PLFLT) xmax, (PLFLT) ymin, (PLFLT) ymax );
949 }
950
951 //--------------------------------------------------------------------------
952 // plr_state()
953 //
954 // Handle change in PLStream state (color, pen width, fill attribute, etc).
955 //--------------------------------------------------------------------------
956
957 static void
plr_state(U_CHAR op)958 plr_state( U_CHAR op )
959 {
960 int i;
961
962 dbug_enter( "plr_state" );
963
964 switch ( op )
965 {
966 case PLSTATE_WIDTH: {
967 U_SHORT width;
968
969 plm_rd( pdf_rd_2bytes( pdfs, &width ) );
970
971 plwidth( width );
972 break;
973 }
974
975 case PLSTATE_COLOR0: {
976 if ( strcmp( mf_version, "2005a" ) >= 0 )
977 {
978 short icol0;
979 plm_rd( pdf_rd_2bytes( pdfs, &icol0 ) );
980
981 if ( icol0 == PL_RGB_COLOR )
982 {
983 U_CHAR r, g, b;
984 plm_rd( pdf_rd_1byte( pdfs, &r ) );
985 plm_rd( pdf_rd_1byte( pdfs, &g ) );
986 plm_rd( pdf_rd_1byte( pdfs, &b ) );
987 plscol0( icol0, r, g, b );
988 }
989 else
990 {
991 plcol0( icol0 );
992 }
993 }
994 else if ( strcmp( mf_version, "1993a" ) >= 0 )
995 {
996 U_CHAR icol0;
997 plm_rd( pdf_rd_1byte( pdfs, &icol0 ) );
998
999 if ( icol0 == 1 << 7 )
1000 {
1001 U_CHAR r, g, b;
1002 plm_rd( pdf_rd_1byte( pdfs, &r ) );
1003 plm_rd( pdf_rd_1byte( pdfs, &g ) );
1004 plm_rd( pdf_rd_1byte( pdfs, &b ) );
1005 plscol0( PL_RGB_COLOR, r, g, b );
1006 }
1007 else
1008 {
1009 plcol0( icol0 );
1010 }
1011 }
1012 else
1013 {
1014 U_SHORT icol;
1015 plm_rd( pdf_rd_2bytes( pdfs, &icol ) );
1016 plcol0( icol );
1017 }
1018 break;
1019 }
1020
1021 case PLSTATE_COLOR1: {
1022 U_SHORT icol1;
1023 PLFLT col1;
1024
1025 plm_rd( pdf_rd_2bytes( pdfs, &icol1 ) );
1026 col1 = (PLFLT) icol1 / (PLFLT) plsc->ncol1;
1027 plcol1( col1 );
1028 break;
1029 }
1030
1031 case PLSTATE_FILL: {
1032 signed char patt;
1033
1034 plm_rd( pdf_rd_1byte( pdfs, (U_CHAR *) &patt ) );
1035 plpsty( patt );
1036 break;
1037 }
1038
1039 case PLSTATE_CMAP0: {
1040 if ( strcmp( mf_version, "2005a" ) >= 0 )
1041 {
1042 U_SHORT ncol0;
1043 plm_rd( pdf_rd_2bytes( pdfs, &ncol0 ) );
1044 plscmap0n( ncol0 );
1045 }
1046 else
1047 {
1048 U_CHAR ncol0;
1049 plm_rd( pdf_rd_1byte( pdfs, &ncol0 ) );
1050 plscmap0n( ncol0 );
1051 }
1052 for ( i = 0; i < plsc->ncol0; i++ )
1053 {
1054 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap0[i].r ) );
1055 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap0[i].g ) );
1056 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap0[i].b ) );
1057 }
1058 if ( plsc->level > 0 )
1059 plP_state( PLSTATE_CMAP0 );
1060
1061 break;
1062 }
1063
1064 case PLSTATE_CMAP1: {
1065 U_SHORT ncol1;
1066
1067 plm_rd( pdf_rd_2bytes( pdfs, &ncol1 ) );
1068 plscmap1n( ncol1 );
1069 for ( i = 0; i < plsc->ncol1; i++ )
1070 {
1071 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap1[i].r ) );
1072 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap1[i].g ) );
1073 plm_rd( pdf_rd_1byte( pdfs, &plsc->cmap1[i].b ) );
1074 }
1075 if ( plsc->level > 0 )
1076 plP_state( PLSTATE_CMAP1 );
1077
1078 break;
1079 }
1080
1081 case PLSTATE_CHR: {
1082 // Disabled for now because the 2005 version does not
1083 // support this command
1084 //plm_rd( pdf_rd_ieeef( pdfs, &plsc->chrdef ) );
1085 //plm_rd( pdf_rd_ieeef( pdfs, &plsc->chrht ) );
1086 break;
1087 }
1088
1089 case PLSTATE_SYM: {
1090 // Disabled for now because the 2005 version does not
1091 // support this command
1092 //plm_rd( pdf_rd_ieeef( pdfs, &plsc->symdef ) );
1093 //plm_rd( pdf_rd_ieeef( pdfs, &plsc->symht ) );
1094 break;
1095 }
1096 }
1097
1098 DEBUG_PRINT_LOCATION( "end of plr_state" );
1099 }
1100
1101 //--------------------------------------------------------------------------
1102 // plr_esc()
1103 //
1104 // Handle all escape functions.
1105 //--------------------------------------------------------------------------
1106
1107 static void
plr_esc(U_CHAR c)1108 plr_esc( U_CHAR c )
1109 {
1110 U_CHAR op;
1111
1112 dbug_enter( "plr_esc" );
1113
1114 plm_rd( pdf_rd_1byte( pdfs, &op ) );
1115
1116 switch ( op )
1117 {
1118 case PLESC_FILL:
1119 plresc_fill();
1120 break;
1121
1122 // These are all commands that should be absent from current metafiles but
1123 // are recognized here for backward compatibility with old metafiles
1124
1125 case PLESC_SET_RGB:
1126 plresc_rgb();
1127 return;
1128
1129 case PLESC_ALLOC_NCOL:
1130 plresc_ancol();
1131 return;
1132
1133 case PLESC_SET_LPB:
1134 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1135 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1136 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1137 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1138 return;
1139 }
1140 }
1141
1142 //--------------------------------------------------------------------------
1143 // plresc_fill()
1144 //
1145 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
1146 //--------------------------------------------------------------------------
1147
1148 static void
plresc_fill(void)1149 plresc_fill( void )
1150 {
1151 dbug_enter( "plresc_fill" );
1152
1153 plm_rd( pdf_rd_2bytes( pdfs, &npts ) );
1154 get_ncoords( x, y, npts );
1155 plfill( npts, x, y );
1156 }
1157
1158 //--------------------------------------------------------------------------
1159 // plresc_rgb()
1160 //
1161 // Process escape function for RGB color selection.
1162 // Note that RGB color selection is no longer handled this way by
1163 // PLplot but we must handle it here for old metafiles.
1164 //--------------------------------------------------------------------------
1165
1166 static void
plresc_rgb(void)1167 plresc_rgb( void )
1168 {
1169 PLFLT red, green, blue;
1170 U_SHORT ired, igreen, iblue;
1171
1172 dbug_enter( "plresc_rgb" );
1173
1174 plm_rd( pdf_rd_2bytes( pdfs, &ired ) );
1175 plm_rd( pdf_rd_2bytes( pdfs, &igreen ) );
1176 plm_rd( pdf_rd_2bytes( pdfs, &iblue ) );
1177
1178 red = (double) ired / 65535.;
1179 green = (double) igreen / 65535.;
1180 blue = (double) iblue / 65535.;
1181
1182 plscol0( PL_RGB_COLOR, red, green, blue );
1183 }
1184
1185 //--------------------------------------------------------------------------
1186 // plresc_ancol()
1187 //
1188 // Process escape function for named color table allocation.
1189 // OBSOLETE -- just read the info and move on.
1190 //--------------------------------------------------------------------------
1191
1192 static void
plresc_ancol(void)1193 plresc_ancol( void )
1194 {
1195 U_CHAR icolor;
1196 char name[80];
1197
1198 dbug_enter( "plresc_ancol" );
1199
1200 plm_rd( pdf_rd_1byte( pdfs, &icolor ) );
1201 plm_rd( pdf_rd_header( pdfs, name ) );
1202 }
1203
1204 //--------------------------------------------------------------------------
1205 // Support routines
1206 //--------------------------------------------------------------------------
1207
1208 //--------------------------------------------------------------------------
1209 // NextFamilyFile()
1210 //
1211 // Start the next family if it exists.
1212 //--------------------------------------------------------------------------
1213
1214 static void
NextFamilyFile(U_CHAR * c)1215 NextFamilyFile( U_CHAR *c )
1216 {
1217 dbug_enter( "NextFamilyFile" );
1218
1219 (void) fclose( MetaFile );
1220 member++;
1221 (void) sprintf( FileName, "%s.%i", BaseName, (int) member );
1222
1223 if ( ( MetaFile = fopen( FileName, "rb" ) ) == NULL )
1224 {
1225 is_family = 0;
1226 return;
1227 }
1228 if ( ReadFileHeader() )
1229 {
1230 is_family = 0;
1231 return;
1232 }
1233 pdfs->file = MetaFile;
1234
1235 //
1236 // If the family file was created correctly, the first instruction in the
1237 // file (after state information) MUST be an INITIALIZE. We throw this
1238 // away; a BOP0 will follow immediately thereafter.
1239 //
1240
1241 *c = getcommand();
1242 while ( *c == CHANGE_STATE )
1243 {
1244 plr_state( getcommand() );
1245 *c = getcommand();
1246 }
1247
1248 if ( *c != INITIALIZE )
1249 fprintf( stderr,
1250 "First instruction in member file not an INITIALIZE!\n" );
1251 else
1252 {
1253 // Update position offset
1254
1255 if ( pl_fgetpos( MetaFile, &curpage_loc ) )
1256 plr_exit( "plrender: fgetpos call failed" );
1257
1258 *c = getcommand();
1259 if ( !( *c == BOP0 || *c == BOP ) )
1260 fprintf( stderr,
1261 "First instruction after INITIALIZE not a BOP!\n" );
1262 }
1263
1264 pldebug( "NextFamilyFile", "successfully opened %s\n", FileName );
1265 DEBUG_PRINT_LOCATION( "end of NextFamilyFile" );
1266 }
1267
1268 //--------------------------------------------------------------------------
1269 // PrevFamilyFile()
1270 //
1271 // Go back to the previous family file.
1272 //--------------------------------------------------------------------------
1273
1274 static void
PrevFamilyFile(void)1275 PrevFamilyFile( void )
1276 {
1277 dbug_enter( "PrevFamilyFile" );
1278
1279 if ( member <= 0 )
1280 return;
1281
1282 (void) fclose( MetaFile );
1283 member--;
1284 (void) sprintf( FileName, "%s.%i", BaseName, (int) member );
1285
1286 if ( ( MetaFile = fopen( FileName, "rb" ) ) == NULL )
1287 {
1288 is_family = 0;
1289 return;
1290 }
1291 if ( ReadFileHeader() )
1292 {
1293 is_family = 0;
1294 return;
1295 }
1296 pdfs->file = MetaFile;
1297
1298 pldebug( "PrevFamilyFile", "successfully opened %s\n", FileName );
1299 DEBUG_PRINT_LOCATION( "end of PrevFamilyFile" );
1300 }
1301
1302 //--------------------------------------------------------------------------
1303 // getcommand()
1304 //
1305 // Read & return the next command
1306 //--------------------------------------------------------------------------
1307
1308 static U_CHAR
getcommand(void)1309 getcommand( void )
1310 {
1311 int c;
1312
1313 c = getc( MetaFile );
1314 if ( c == EOF )
1315 plr_exit( "getcommand: Unable to read from MetaFile" );
1316
1317 return (U_CHAR) c;
1318 }
1319
1320 //--------------------------------------------------------------------------
1321 // ungetcommand()
1322 //
1323 // Push back the last command read.
1324 //--------------------------------------------------------------------------
1325
1326 static void
ungetcommand(U_CHAR c)1327 ungetcommand( U_CHAR c )
1328 {
1329 if ( ungetc( c, MetaFile ) == EOF )
1330 plr_exit( "ungetcommand: Unable to push back character" );
1331 }
1332
1333 //--------------------------------------------------------------------------
1334 // void plr_exit()
1335 //
1336 // In case of an abort this routine is called. Unlike plexit(), it does
1337 // NOT turn off pause, so that if a problem occurs you can still see what
1338 // output remains on the screen before the program terminates.
1339 //--------------------------------------------------------------------------
1340
1341 static void
plr_exit(char * errormsg)1342 plr_exit( char *errormsg )
1343 {
1344 int status = 1;
1345
1346 plend();
1347 if ( *errormsg != '\0' )
1348 {
1349 fprintf( stderr, "\n*** PLRENDER ERROR ***\n" );
1350 fprintf( stderr, "%s\n", errormsg );
1351 }
1352
1353 fprintf( stderr, "Program aborted\n" );
1354
1355 // For really bad debugging cases, you may want to see what the next bit of
1356 // metafile looked like.
1357 //
1358
1359 #ifdef DEBUG
1360 {
1361 int i, imax = 256, c_end;
1362 fprintf( stderr, "next %d chars in metafile are:\n", imax );
1363 for ( i = 1; i < imax; i++ )
1364 {
1365 c_end = getc( MetaFile );
1366 if ( c_end == EOF )
1367 break;
1368 fprintf( stderr, " %d", c_end );
1369 }
1370 fprintf( stderr, "\n" );
1371 }
1372 #endif
1373
1374 exit( status );
1375 }
1376
1377 //--------------------------------------------------------------------------
1378 // plr_KeyEH()
1379 //
1380 // Keyboard event handler. For mapping keyboard sequences to commands
1381 // not usually supported by PLplot, such as seeking around in the
1382 // metafile. Recognized commands:
1383 //
1384 // <Backspace> |
1385 // <Delete> | Back page
1386 // <Page up> |
1387 //
1388 // +<num><CR> Seek forward <num> pages.
1389 // -<num><CR> Seek backward <num> pages.
1390 //
1391 // <num><CR> Seek to page <num>.
1392 // --<num><CR> Seek to <num> pages before EOF.
1393 //
1394 // Both <BS> and <DEL> are recognized for a back-page since the target
1395 // system may use either as its erase key. <Page Up> is present on some
1396 // keyboards (different from keypad key).
1397 //
1398 // No user data is passed in this case, although a test case is
1399 // illustrated.
1400 //
1401 // Illegal input is ignored.
1402 //--------------------------------------------------------------------------
1403
1404 static void
plr_KeyEH(PLGraphicsIn * gin,void * user_data,int * p_exit_eventloop)1405 plr_KeyEH( PLGraphicsIn *gin, void *user_data, int *p_exit_eventloop )
1406 {
1407 char *tst = (char *) user_data;
1408 int input_num, dun_seek = 0, terminator_seen = 0;
1409
1410 pldebug( "plr_KeyEH", "gin->keysym = %x\n", gin->keysym );
1411
1412 // TEST
1413
1414 if ( tst != NULL )
1415 {
1416 pltext();
1417 fprintf( stderr, "tst string: %s\n", tst );
1418 plgra();
1419 }
1420
1421 // The rest deals with seeking only; so we return if it is disabled
1422
1423 if ( no_pagelinks || !isfile )
1424 return;
1425
1426 // Forward (+) or backward (-)
1427
1428 if ( gin->string[0] == '+' )
1429 direction_flag++;
1430
1431 else if ( gin->string[0] == '-' )
1432 direction_flag--;
1433
1434 // If a number, store into num_buffer
1435
1436 if ( isdigit( gin->string[0] ) )
1437 {
1438 isanum = TRUE;
1439 (void) strncat( num_buffer, gin->string, ( 20 - strlen( num_buffer ) ) );
1440 }
1441
1442 //
1443 // Seek to specified page, or page advance.
1444 // Not done until user hits <return>.
1445 // Need to check for both <LF> and <CR> for portability.
1446 //
1447 if ( gin->keysym == PLK_Return ||
1448 gin->keysym == PLK_Linefeed ||
1449 gin->keysym == PLK_Next )
1450 {
1451 terminator_seen = 1;
1452 if ( isanum )
1453 {
1454 input_num = atoi( num_buffer );
1455 if ( input_num == 0 )
1456 {
1457 if ( strcmp( num_buffer, "0" ) )
1458 input_num = -1;
1459 }
1460 if ( input_num >= 0 )
1461 {
1462 if ( direction_flag == 0 )
1463 target_disp = input_num;
1464 else if ( direction_flag == 1 )
1465 target_disp = curdisp + input_num;
1466 else if ( direction_flag == -1 )
1467 target_disp = curdisp - input_num;
1468 else if ( direction_flag == -2 )
1469 target_disp = pages - input_num;
1470
1471 SeekToDisp( target_disp );
1472 dun_seek = 1;
1473 }
1474 }
1475 else
1476 {
1477 target_disp = curdisp + 1;
1478 SeekToDisp( target_disp );
1479 dun_seek = 1;
1480 }
1481 }
1482
1483 // Page backward
1484
1485 if ( gin->keysym == PLK_BackSpace ||
1486 gin->keysym == PLK_Delete ||
1487 gin->keysym == PLK_Prior )
1488 {
1489 terminator_seen = 1;
1490 target_disp = curdisp - 1;
1491 SeekToDisp( target_disp );
1492 dun_seek = 1;
1493 }
1494
1495 // Cleanup
1496
1497 if ( terminator_seen )
1498 {
1499 num_buffer[0] = '\0';
1500 direction_flag = 0;
1501 isanum = 0;
1502 gin->keysym = 0;
1503 }
1504 if ( dun_seek && at_eop )
1505 *p_exit_eventloop = TRUE;
1506 }
1507
1508 //--------------------------------------------------------------------------
1509 // SeekToDisp()
1510 //
1511 // Seek to 'target_disp' displayed page.
1512 //
1513 // Several things combine to make this much harder than one would think.
1514 // These include: taking packed pages into account, seeking from mid-plot,
1515 // and multiple contiguous seek events. All in all a disgusting mess.
1516 //
1517 // When this routine is called we are probably at the end of a page, but
1518 // maybe not (e.g. if the user hit <Backspace> or <Return> in the middle
1519 // of the screen update, and the driver immediately processes the event).
1520 // Also we might be at the end of the file. So only if we are right
1521 // before the desired displayed page AND the end of page condition is met,
1522 // we are done.
1523 //
1524 // When reference is made to a displayed (i.e. possibly packed) page, I
1525 // will use variables with the "disp" tag. For metafile pages, I will
1526 // use "page". I could have used the word "plot" somewhere but I am
1527 // reserving that for future uses.
1528 //
1529 // To deal with multiple contiguous seek events (e.g. the user hits
1530 // <Backspace> twice before the renderer has a chance to respond) the
1531 // "seek_mode" variable was found to be necessary.
1532 //--------------------------------------------------------------------------
1533
1534 static void
SeekToDisp(long target_disp)1535 SeekToDisp( long target_disp )
1536 {
1537 dbug_enter( "SeekToDisp" );
1538
1539 // Determine target_page
1540 // Needs to be the last subpage on the preceding displayed page,
1541 // so we subtract 1 unless the last seek is still active
1542
1543 if ( !seek_mode )
1544 --target_disp;
1545
1546 target_page = target_disp * nsubx * nsuby;
1547 delta = target_page - curpage;
1548 seek_mode = 1;
1549
1550 // Handle special cases first -- none of these require seeks.
1551 // An example of how each condition might arise is given.
1552
1553 // <Return> at the end of a page
1554
1555 if ( ( delta == 0 ) && at_eop )
1556 return;
1557
1558 // <Return> while drawing the last page
1559
1560 if ( ( delta >= 0 ) && ( nextpage_loc == 0 ) )
1561 return;
1562
1563 // Anything else requires at least one seek
1564
1565 pldebug( "SeekToDisp",
1566 "Before seek: target_page = %d, curpage = %d, curdisp = %d\n",
1567 target_page, curpage, curdisp );
1568
1569 // <Return> while drawing any page but the last
1570
1571 if ( delta == 0 )
1572 {
1573 SeekToNextPage();
1574 goto done;
1575 }
1576
1577 // Prepare for backward seeks by seeking to the start of the current page
1578 // If on the first page, we're done
1579
1580 if ( delta < 0 )
1581 {
1582 SeekToCurPage();
1583 if ( prevpage_loc == 0 )
1584 goto done;
1585 }
1586
1587 // Now seek by pages until we arrive at the target page
1588
1589 while ( delta != 0 )
1590 SeekOnePage();
1591
1592 done:
1593 pldebug( "SeekToDisp",
1594 "After seek: curpage = %d, curdisp = %d, cursub = %d\n",
1595 curpage, curdisp, cursub );
1596
1597 end_of_page = 1;
1598 return;
1599 }
1600
1601 //--------------------------------------------------------------------------
1602 // SeekOnePage()
1603 //
1604 // Seeks one page in appropriate direction, and updates delta.
1605 // For out of bounds seeks, just stay on the boundary page (first or last).
1606 //--------------------------------------------------------------------------
1607
1608 static void
SeekOnePage(void)1609 SeekOnePage( void )
1610 {
1611 if ( delta > 0 )
1612 {
1613 if ( nextpage_loc == 0 )
1614 {
1615 SeekToCurPage();
1616 delta = 0;
1617 return;
1618 }
1619 SeekToNextPage();
1620 }
1621 else
1622 {
1623 if ( prevpage_loc == 0 )
1624 {
1625 SeekToCurPage();
1626 delta = 0;
1627 return;
1628 }
1629 SeekToPrevPage();
1630 }
1631
1632 delta = target_page - curpage;
1633 pldebug( "SeekOnePage", "Now at page %d, disp %d, delta %d\n",
1634 curpage, curdisp, delta );
1635
1636 return;
1637 }
1638
1639 //--------------------------------------------------------------------------
1640 // SeekToCurPage()
1641 //
1642 // Seeks to beginning of current page, changing the page counters if
1643 // we pass a page boundary in the process. Are you sufficiently sick
1644 // yet? I know I am.
1645 //--------------------------------------------------------------------------
1646
1647 static void
SeekToCurPage(void)1648 SeekToCurPage( void )
1649 {
1650 FPOS_T loc;
1651
1652 if ( pl_fgetpos( MetaFile, &loc ) )
1653 plr_exit( "plrender: fgetpos call failed" );
1654
1655 if ( loc != curpage_loc )
1656 PageDecr();
1657
1658 SeekTo( curpage_loc );
1659 }
1660
1661 //--------------------------------------------------------------------------
1662 // SeekToNextPage()
1663 //
1664 // Seeks to beginning of next page, changing the page counters if
1665 // we pass a page boundary in the process.
1666 //--------------------------------------------------------------------------
1667
1668 static void
SeekToNextPage(void)1669 SeekToNextPage( void )
1670 {
1671 FPOS_T loc;
1672
1673 if ( pl_fgetpos( MetaFile, &loc ) )
1674 plr_exit( "plrender: fgetpos call failed" );
1675
1676 if ( loc == curpage_loc )
1677 PageIncr();
1678
1679 SeekTo( nextpage_loc );
1680 }
1681
1682 //--------------------------------------------------------------------------
1683 // SeekToPrevPage()
1684 //
1685 // Seeks to beginning of previous page, changing page counters to
1686 // take into account each page header we skip over. Getting sicker
1687 // all the time..
1688 //--------------------------------------------------------------------------
1689
1690 static void
SeekToPrevPage(void)1691 SeekToPrevPage( void )
1692 {
1693 FPOS_T loc;
1694
1695 dbug_enter( "SeekToPrevPage" );
1696
1697 if ( pl_fgetpos( MetaFile, &loc ) )
1698 plr_exit( "plrender: fgetpos call failed" );
1699
1700 if ( loc != curpage_loc )
1701 PageDecr();
1702
1703 if ( is_family && first_page )
1704 PrevFamilyFile();
1705
1706 SeekTo( prevpage_loc );
1707 PageDecr();
1708 }
1709
1710 //--------------------------------------------------------------------------
1711 // SeekTo()
1712 //
1713 // Seeks to specified location, updating page links.
1714 //--------------------------------------------------------------------------
1715
1716 static void
SeekTo(FPOS_T loc)1717 SeekTo( FPOS_T loc )
1718 {
1719 pldebug( "SeekTo", "Seeking to: %d\n", loc );
1720 doseek( loc );
1721
1722 // Update page links
1723
1724 ReadPageHeader();
1725 doseek( curpage_loc );
1726 PageDecr();
1727 }
1728
1729 //--------------------------------------------------------------------------
1730 // Utility functions:
1731 //
1732 // doseek() Seeks to the specified location in the file.
1733 // PageIncr() Increments page counters
1734 // PageDecr() Decrements page counters
1735 //--------------------------------------------------------------------------
1736
1737 static void
doseek(FPOS_T loc)1738 doseek( FPOS_T loc )
1739 {
1740 if ( pl_fsetpos( MetaFile, &loc ) )
1741 plr_exit( "plrender: fsetpos call failed" );
1742 }
1743
1744 static void
PageDecr(void)1745 PageDecr( void )
1746 {
1747 curpage--;
1748 cursub--;
1749 if ( cursub < 1 )
1750 {
1751 cursub = nsubx * nsuby;
1752 curdisp--;
1753 }
1754 }
1755
1756 static void
PageIncr(void)1757 PageIncr( void )
1758 {
1759 cursub++;
1760 curpage++;
1761 if ( cursub > nsubx * nsuby )
1762 {
1763 cursub = 1;
1764 curdisp++;
1765 }
1766 }
1767
1768 // Yes, finally done with the seek routines.
1769 // "BELIEVE IT!" - John Walker, from "Buckaroo Bonzai"
1770
1771 //--------------------------------------------------------------------------
1772 // ReadPageHeader()
1773 //
1774 // Reads the metafile, processing page header info.
1775 // Assumes the file pointer is positioned immediately before a BOP.
1776 //--------------------------------------------------------------------------
1777
1778 static void
ReadPageHeader(void)1779 ReadPageHeader( void )
1780 {
1781 U_CHAR c;
1782 U_SHORT page;
1783 U_LONG prevpage, nextpage;
1784
1785 dbug_enter( "ReadPageHeader" );
1786
1787 DEBUG_PRINT_LOCATION( "beginning of ReadPageHeader" );
1788
1789 // Read page header
1790
1791 if ( isfile )
1792 {
1793 if ( pl_fgetpos( MetaFile, &curpage_loc ) )
1794 plr_exit( "plrender: fgetpos call failed" );
1795 }
1796
1797 c = getcommand();
1798 if ( c == CLOSE && is_family )
1799 NextFamilyFile( &c );
1800
1801 if ( !( c == BOP0 || c == BOP || c == ADVANCE ) )
1802 {
1803 sprintf( buffer, "plrender: page advance expected; found command code %d\n \
1804 file: %s, position: %d", c, FileName, (int) curpage_loc );
1805 plr_exit( buffer );
1806 }
1807
1808 first_page = ( c == BOP0 );
1809
1810 // Update page/subpage counters and update page links
1811
1812 PageIncr();
1813
1814 if ( strcmp( mf_version, "1992a" ) >= 0 )
1815 {
1816 if ( strcmp( mf_version, "1993a" ) >= 0 )
1817 {
1818 plm_rd( pdf_rd_2bytes( pdfs, &page ) );
1819 plm_rd( pdf_rd_4bytes( pdfs, &prevpage ) );
1820 plm_rd( pdf_rd_4bytes( pdfs, &nextpage ) );
1821 prevpage_loc = prevpage;
1822 nextpage_loc = nextpage;
1823 pldebug( "ReadPageHeader",
1824 "page: %d, prev page offset: %d, next page offset: %d\n",
1825 (int) page, (int) prevpage, (int) nextpage );
1826 }
1827 else
1828 {
1829 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1830 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1831 }
1832 }
1833 pldebug( "ReadPageHeader", "Now at page %d, disp %d\n", curpage, curdisp );
1834 DEBUG_PRINT_LOCATION( "end of ReadPageHeader" );
1835 }
1836
1837 //--------------------------------------------------------------------------
1838 // ReadFileHeader()
1839 //
1840 // Checks file header. Returns 1 if an error occured.
1841 //--------------------------------------------------------------------------
1842
1843 static int
ReadFileHeader(void)1844 ReadFileHeader( void )
1845 {
1846 char tag[80];
1847
1848 dbug_enter( "ReadFileHeader" );
1849
1850 // Read label field of header to make sure file is a PLplot metafile
1851
1852 plm_rd( pdf_rd_header( pdfs, mf_magic ) );
1853 if ( strcmp( mf_magic, PLMETA_HEADER ) )
1854 {
1855 fprintf( stderr, "Not a PLplot metafile!\n" );
1856 return 1;
1857 }
1858
1859 // Read version field of header. We need to check that we can read the
1860 // metafile, in case this is an old version of plrender.
1861
1862 plm_rd( pdf_rd_header( pdfs, mf_version ) );
1863 if ( strcmp( mf_version, PLMETA_VERSION ) > 0 )
1864 {
1865 fprintf( stderr,
1866 "Error: incapable of reading metafile version %s.\n", mf_version );
1867 fprintf( stderr, "Please obtain a newer copy of plrender.\n" );
1868 return 1;
1869 }
1870 pldebug( "ReadFileHeader", "Metafile version %s\n", mf_version );
1871
1872 // Disable page seeking on versions without page links
1873
1874 if ( strcmp( mf_version, "1993a" ) < 0 )
1875 no_pagelinks = 1;
1876
1877 // Return if metafile older than version 1992a (no tagged info).
1878
1879 if ( strcmp( mf_version, "1992a" ) < 0 )
1880 {
1881 return 0;
1882 }
1883
1884 // Read tagged initialization info.
1885 // This is an easy way to guarantee backward compatibility.
1886
1887 for (;; )
1888 {
1889 plm_rd( pdf_rd_header( pdfs, tag ) );
1890 if ( *tag == '\0' )
1891 break;
1892
1893 pldebug( "ReadFileHeader",
1894 "Read tag: %s\n", tag );
1895
1896 if ( !strcmp( tag, "pages" ) )
1897 {
1898 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1899 pages = dum_ushort;
1900 continue;
1901 }
1902
1903 if ( !strcmp( tag, "xmin" ) )
1904 {
1905 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1906 xmin = dum_ushort;
1907 continue;
1908 }
1909
1910 if ( !strcmp( tag, "xmax" ) )
1911 {
1912 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1913 xmax = dum_ushort;
1914 continue;
1915 }
1916
1917 if ( !strcmp( tag, "ymin" ) )
1918 {
1919 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1920 ymin = dum_ushort;
1921 continue;
1922 }
1923
1924 if ( !strcmp( tag, "ymax" ) )
1925 {
1926 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1927 ymax = dum_ushort;
1928 continue;
1929 }
1930
1931 if ( !strcmp( tag, "pxlx" ) )
1932 {
1933 plm_rd( pdf_rd_ieeef( pdfs, &pxlx ) );
1934 continue;
1935 }
1936
1937 if ( !strcmp( tag, "pxly" ) )
1938 {
1939 plm_rd( pdf_rd_ieeef( pdfs, &pxly ) );
1940 continue;
1941 }
1942
1943 if ( !strcmp( tag, "width" ) )
1944 {
1945 plm_rd( pdf_rd_1byte( pdfs, &dum_uchar ) );
1946 plwidth( dum_uchar );
1947 continue;
1948 }
1949
1950 // Geometry info
1951
1952 if ( !strcmp( tag, "xdpi" ) )
1953 {
1954 plm_rd( pdf_rd_ieeef( pdfs, &xdpi ) );
1955 continue;
1956 }
1957
1958 if ( !strcmp( tag, "ydpi" ) )
1959 {
1960 plm_rd( pdf_rd_ieeef( pdfs, &ydpi ) );
1961 continue;
1962 }
1963
1964 if ( !strcmp( tag, "xlength" ) )
1965 {
1966 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1967 xlength = dum_ushort;
1968 continue;
1969 }
1970
1971 if ( !strcmp( tag, "ylength" ) )
1972 {
1973 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1974 ylength = dum_ushort;
1975 continue;
1976 }
1977
1978 if ( !strcmp( tag, "xoffset" ) )
1979 {
1980 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1981 xoffset = dum_ushort;
1982 continue;
1983 }
1984
1985 if ( !strcmp( tag, "yoffset" ) )
1986 {
1987 plm_rd( pdf_rd_2bytes( pdfs, &dum_ushort ) );
1988 yoffset = dum_ushort;
1989 continue;
1990 }
1991
1992 // Obsolete tags
1993
1994 if ( !strcmp( tag, "orient" ) )
1995 {
1996 plm_rd( pdf_rd_1byte( pdfs, &dum_uchar ) );
1997 continue;
1998 }
1999
2000 if ( !strcmp( tag, "aspect" ) )
2001 {
2002 plm_rd( pdf_rd_ieeef( pdfs, &dum_float ) );
2003 continue;
2004 }
2005
2006 fprintf( stderr, "Unrecognized PLplot metafile header tag.\n" );
2007 exit( EX_BADFILE );
2008 }
2009
2010 DEBUG_PRINT_LOCATION( "end of ReadFileHeader" );
2011 return 0;
2012 }
2013
2014 //--------------------------------------------------------------------------
2015 // Input handlers
2016 //--------------------------------------------------------------------------
2017
2018 //--------------------------------------------------------------------------
2019 // Opt_v()
2020 //
2021 // Performs appropriate action for option "v".
2022 //
2023 // Note: the return code of 1 and the PL_OPT_NODELETE option tag ensures
2024 // that processing continues after Opt_v() returns, to pick up the internal
2025 // -v handling.
2026 //--------------------------------------------------------------------------
2027
2028 static int
Opt_v(const char * opt,const char * optarg,void * client_data)2029 Opt_v( const char *opt, const char *optarg, void *client_data )
2030 {
2031 // Version
2032
2033 fprintf( stderr, "PLplot metafile version: %s\n", PLMETA_VERSION );
2034 return 1;
2035 }
2036
2037 //--------------------------------------------------------------------------
2038 // Opt_i()
2039 //
2040 // Performs appropriate action for option "i".
2041 //--------------------------------------------------------------------------
2042
2043 static int
Opt_i(const char * opt,const char * optarg,void * client_data)2044 Opt_i( const char *opt, const char *optarg, void *client_data )
2045 {
2046 // Input file
2047
2048 strncpy( FileName, optarg, sizeof ( FileName ) - 1 );
2049 FileName[sizeof ( FileName ) - 1] = '\0';
2050 do_file_loop = 0;
2051
2052 return 0;
2053 }
2054
2055 //--------------------------------------------------------------------------
2056 // Opt_b()
2057 //
2058 // Performs appropriate action for option "b".
2059 //--------------------------------------------------------------------------
2060
2061 static int
Opt_b(const char * opt,const char * optarg,void * client_data)2062 Opt_b( const char *opt, const char *optarg, void *client_data )
2063 {
2064 // Beginning page
2065
2066 if ( *optarg == '-' )
2067 {
2068 optarg++;
2069 addeof_beg = 1;
2070 }
2071 disp_beg = atoi( optarg );
2072
2073 return 0;
2074 }
2075
2076 //--------------------------------------------------------------------------
2077 // Opt_e()
2078 //
2079 // Performs appropriate action for option "e".
2080 //--------------------------------------------------------------------------
2081
2082 static int
Opt_e(const char * opt,const char * optarg,void * client_data)2083 Opt_e( const char *opt, const char *optarg, void *client_data )
2084 {
2085 // Ending page
2086
2087 if ( *optarg == '-' )
2088 {
2089 optarg++;
2090 addeof_end = 1;
2091 }
2092 disp_end = atoi( optarg );
2093
2094 return 0;
2095 }
2096
2097 //--------------------------------------------------------------------------
2098 // Opt_p()
2099 //
2100 // Performs appropriate action for option "p".
2101 //--------------------------------------------------------------------------
2102
2103 static int
Opt_p(const char * opt,const char * optarg,void * client_data)2104 Opt_p( const char *opt, const char *optarg, void *client_data )
2105 {
2106 // Specified page only
2107
2108 if ( *optarg == '-' )
2109 {
2110 optarg++;
2111 addeof_beg = 1;
2112 addeof_end = 1;
2113 }
2114 disp_beg = atoi( optarg );
2115 disp_end = disp_beg;
2116
2117 return 0;
2118 }
2119