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, &current_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