PLplot  5.10.0
plcore.c
Go to the documentation of this file.
00001 //      Central dispatch facility for PLplot.
00002 //      Also contains the PLplot main data structures, external access
00003 //      routines, and initialization calls.
00004 //
00005 //      This stuff used to be in "dispatch.h", "dispatch.c", and "base.c".
00006 //
00007 //
00008 // Copyright (C) 2004  Joao Cardoso
00009 // Copyright (C) 2004, 2005  Rafael Laboissiere
00010 // Copyright (C) 2004, 2006  Andrew Ross
00011 // Copyright (C) 2004  Andrew Roach
00012 // Copyright (C) 2005-2014 Alan W. Irwin
00013 // Copyright (C) 2005  Thomas J. Duck
00014 //
00015 // This file is part of PLplot.
00016 //
00017 // PLplot is free software; you can redistribute it and/or modify
00018 // it under the terms of the GNU Library General Public License as published
00019 // by the Free Software Foundation; either version 2 of the License, or
00020 // (at your option) any later version.
00021 //
00022 // PLplot is distributed in the hope that it will be useful,
00023 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025 // GNU Library General Public License for more details.
00026 //
00027 // You should have received a copy of the GNU Library General Public License
00028 // along with PLplot; if not, write to the Free Software
00029 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00030 //
00031 //
00032 
00033 #define DEBUG
00034 #define NEED_PLDEBUG
00035 #include "plcore.h"
00036 
00037 #ifdef ENABLE_DYNDRIVERS
00038   #ifndef LTDL_WIN32
00039     #include <ltdl.h>
00040   #else
00041     #include "ltdl_win32.h"
00042   #endif
00043 #endif
00044 
00045 #if HAVE_DIRENT_H
00046 // The following conditional is a workaround for a bug in the MacOSX system.
00047 // When  the dirent.h file will be fixed upstream by Apple Inc, this should
00048 // go away.
00049 # ifdef NEED_SYS_TYPE_H
00050 #  include <sys/types.h>
00051 # endif
00052 # include <dirent.h>
00053 # define NAMLEN( dirent )    strlen( ( dirent )->d_name )
00054 #else
00055 # if defined ( _MSC_VER )
00056 #  include "dirent_msvc.h"
00057 # else
00058 #  define dirent    direct
00059 #  define NAMLEN( dirent )    ( dirent )->d_namlen
00060 #  if HAVE_SYS_NDIR_H
00061 #   include <sys/ndir.h>
00062 #  endif
00063 #  if HAVE_SYS_DIR_H
00064 #   include <sys/dir.h>
00065 #  endif
00066 #  if HAVE_NDIR_H
00067 #   include <ndir.h>
00068 #  endif
00069 # endif
00070 #endif
00071 
00072 // AM: getcwd has a somewhat strange status on Windows, its proper
00073 // name is _getcwd, this is a problem in the case of DLLs, like with
00074 // the Java bindings. The functions _getcwd() and chdir() are
00075 // declared in direct.h for Visual C++. Since chdir() is deprecated
00076 // (but still available) in Visual C++ we redefine chdir to _chdir.
00077 //
00078 #if defined ( _MSC_VER )
00079 #  include <direct.h>
00080 #  define getcwd        _getcwd
00081 #  define chdir         _chdir
00082 #endif
00083 
00084 #define BUFFER_SIZE     80
00085 #define BUFFER2_SIZE    300
00086 #define DRVSPEC_SIZE    400
00087 
00088 #include <errno.h>
00089 
00090 int
00091 text2num( const char *text, char end, PLUNICODE *num );
00092 
00093 int
00094 text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower );
00095 
00096 //--------------------------------------------------------------------------
00097 // Driver Interface
00098 //
00099 // These routines are the low-level interface to the driver -- all calls to
00100 // driver functions must pass through here.  For implementing driver-
00101 // specific functions, the escape function is provided.  The command stream
00102 // gets duplicated to the plot buffer here.
00103 //
00104 // All functions that result in graphics actually being plotted (rather than
00105 // just a change of state) are filtered as necessary before being passed on.
00106 // The default settings do not require any filtering, i.e.  PLplot physical
00107 // coordinates are the same as the device physical coordinates (currently
00108 // this can't be changed anyway), and a global view equal to the entire page
00109 // is used.
00110 //
00111 // The reason one wants to put view-specific filtering here is that if
00112 // enabled, the plot buffer should receive the unfiltered data stream.  This
00113 // allows a specific view to be used from an interactive device (e.g. TCL/TK
00114 // driver) but be restored to the full view at any time merely by
00115 // reprocessing the contents of the plot buffer.
00116 //
00117 // The metafile, on the other hand, *should* be affected by changes in the
00118 // view, since this is a crucial editing capability.  It is recommended that
00119 // the initial metafile be created without a restricted global view, and
00120 // modification of the view done on a per-plot basis as desired during
00121 // subsequent processing.
00122 //
00123 //--------------------------------------------------------------------------
00124 
00125 enum { AT_BOP, DRAWING, AT_EOP };
00126 
00127 // Initialize device.
00128 // The plot buffer must be called last.
00129 
00130 // The following array of chars is used both here and in plsym.c for
00131 // translating the Greek characters from the #g escape sequences into
00132 // the Hershey and Unicode codings
00133 //
00134 const char plP_greek_mnemonic[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
00135 
00136 void
00137 plP_init( void )
00138 {
00139     char * save_locale;
00140     plsc->page_status   = AT_EOP;
00141     plsc->stream_closed = FALSE;
00142 
00143     save_locale = plsave_set_locale();
00144     ( *plsc->dispatch_table->pl_init )( (struct PLStream_struct *) plsc );
00145     plrestore_locale( save_locale );
00146 
00147     if ( plsc->plbuf_write )
00148         plbuf_init( plsc );
00149 }
00150 
00151 // End of page
00152 // The plot buffer must be called first.
00153 // Ignore instruction if already at eop.
00154 
00155 void
00156 plP_eop( void )
00157 {
00158     int skip_driver_eop = 0;
00159 
00160     if ( plsc->page_status == AT_EOP )
00161         return;
00162 
00163     plsc->page_status = AT_EOP;
00164 
00165     if ( plsc->plbuf_write )
00166         plbuf_eop( plsc );
00167 
00168 // Call user eop handler if present.
00169 
00170     if ( plsc->eop_handler != NULL )
00171         ( *plsc->eop_handler )( plsc->eop_data, &skip_driver_eop );
00172 
00173     if ( !skip_driver_eop )
00174     {
00175         char *save_locale = plsave_set_locale();
00176         if ( !plsc->stream_closed )
00177         {
00178             ( *plsc->dispatch_table->pl_eop )( (struct PLStream_struct *) plsc );
00179         }
00180         plrestore_locale( save_locale );
00181     }
00182 }
00183 
00184 // Set up new page.
00185 // The plot buffer must be called last.
00186 // Ignore if already at bop.
00187 // It's not actually necessary to be AT_EOP here, so don't check for it.
00188 
00189 void
00190 plP_bop( void )
00191 {
00192     int skip_driver_bop = 0;
00193 
00194     plP_subpInit();
00195     if ( plsc->page_status == AT_BOP )
00196         return;
00197 
00198     plsc->page_status = AT_BOP;
00199     plsc->nplwin      = 0;
00200 
00201 // Call user bop handler if present.
00202 
00203     if ( plsc->bop_handler != NULL )
00204         ( *plsc->bop_handler )( plsc->bop_data, &skip_driver_bop );
00205 
00206     if ( !skip_driver_bop )
00207     {
00208         char *save_locale = plsave_set_locale();
00209         if ( !plsc->stream_closed )
00210         {
00211             ( *plsc->dispatch_table->pl_bop )( (struct PLStream_struct *) plsc );
00212         }
00213         plrestore_locale( save_locale );
00214     }
00215 
00216     if ( plsc->plbuf_write )
00217         plbuf_bop( plsc );
00218 }
00219 
00220 // Tidy up device (flush buffers, close file, etc).
00221 
00222 void
00223 plP_tidy( void )
00224 {
00225     char * save_locale;
00226     if ( plsc->tidy )
00227     {
00228         ( *plsc->tidy )( plsc->tidy_data );
00229         plsc->tidy      = NULL;
00230         plsc->tidy_data = NULL;
00231     }
00232 
00233     save_locale = plsave_set_locale();
00234     if ( !plsc->stream_closed )
00235     {
00236         ( *plsc->dispatch_table->pl_tidy )( (struct PLStream_struct *) plsc );
00237     }
00238     plrestore_locale( save_locale );
00239 
00240     if ( plsc->plbuf_write )
00241     {
00242         plbuf_tidy( plsc );
00243     }
00244 
00245     plsc->OutFile = NULL;
00246 }
00247 
00248 // Change state.
00249 
00250 void
00251 plP_state( PLINT op )
00252 {
00253     char * save_locale;
00254     if ( plsc->plbuf_write )
00255         plbuf_state( plsc, op );
00256 
00257     save_locale = plsave_set_locale();
00258     if ( !plsc->stream_closed )
00259     {
00260         ( *plsc->dispatch_table->pl_state )( (struct PLStream_struct *) plsc, op );
00261     }
00262     plrestore_locale( save_locale );
00263 }
00264 
00265 // Escape function, for driver-specific commands.
00266 
00267 void
00268 plP_esc( PLINT op, void *ptr )
00269 {
00270     char   * save_locale;
00271     PLINT  clpxmi, clpxma, clpymi, clpyma;
00272     EscText* args;
00273 
00274     // The plot buffer must be called first
00275     if ( plsc->plbuf_write )
00276         plbuf_esc( plsc, op, ptr );
00277 
00278     // Text coordinates must pass through the driver interface filter
00279     if ( ( op == PLESC_HAS_TEXT && plsc->dev_unicode ) ||
00280          ( op == PLESC_END_TEXT && plsc->alt_unicode ) )
00281     {
00282         // Apply the driver interface filter
00283         if ( plsc->difilt )
00284         {
00285             args = (EscText *) ptr;
00286             difilt( &( args->x ), &( args->y ), 1, &clpxmi, &clpxma, &clpymi, &clpyma );
00287         }
00288     }
00289 
00290     save_locale = plsave_set_locale();
00291     if ( !plsc->stream_closed )
00292     {
00293         ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc, op, ptr );
00294     }
00295     plrestore_locale( save_locale );
00296 }
00297 
00298 // Set up plot window parameters.
00299 // The plot buffer must be called first
00300 // Some drivers (metafile, Tk) need access to this data
00301 
00302 void
00303 plP_swin( PLWindow *plwin )
00304 {
00305     PLWindow *w;
00306     PLINT    clpxmi, clpxma, clpymi, clpyma;
00307 
00308 // Provide plot buffer with unfiltered window data
00309 
00310     if ( plsc->plbuf_write )
00311         plbuf_esc( plsc, PLESC_SWIN, (void *) plwin );
00312 
00313     w = &plsc->plwin[plsc->nplwin++ % PL_MAXWINDOWS];
00314 
00315     w->dxmi = plwin->dxmi;
00316     w->dxma = plwin->dxma;
00317     w->dymi = plwin->dymi;
00318     w->dyma = plwin->dyma;
00319 
00320     if ( plsc->difilt )
00321     {
00322         xscl[0] = plP_dcpcx( w->dxmi );
00323         xscl[1] = plP_dcpcx( w->dxma );
00324         yscl[0] = plP_dcpcy( w->dymi );
00325         yscl[1] = plP_dcpcy( w->dyma );
00326 
00327         difilt( xscl, yscl, 2, &clpxmi, &clpxma, &clpymi, &clpyma );
00328 
00329         w->dxmi = plP_pcdcx( xscl[0] );
00330         w->dxma = plP_pcdcx( xscl[1] );
00331         w->dymi = plP_pcdcy( yscl[0] );
00332         w->dyma = plP_pcdcy( yscl[1] );
00333     }
00334 
00335     w->wxmi = plwin->wxmi;
00336     w->wxma = plwin->wxma;
00337     w->wymi = plwin->wymi;
00338     w->wyma = plwin->wyma;
00339 
00340 // If the driver wants to process swin commands, call it now
00341 // It must use the filtered data, which it can get from *plsc
00342 
00343     if ( plsc->dev_swin )
00344     {
00345         char *save_locale = plsave_set_locale();
00346         if ( !plsc->stream_closed )
00347         {
00348             ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
00349                 PLESC_SWIN, NULL );
00350         }
00351         plrestore_locale( save_locale );
00352     }
00353 }
00354 
00355 //--------------------------------------------------------------------------
00356 //  Drawing commands.
00357 //--------------------------------------------------------------------------
00358 
00359 // Draw line between two points
00360 // The plot buffer must be called first so it gets the unfiltered data
00361 
00362 void
00363 plP_line( short *x, short *y )
00364 {
00365     PLINT i, npts = 2, clpxmi, clpxma, clpymi, clpyma;
00366 
00367     plsc->page_status = DRAWING;
00368 
00369     if ( plsc->plbuf_write )
00370         plbuf_line( plsc, x[0], y[0], x[1], y[1] );
00371 
00372     if ( plsc->difilt )
00373     {
00374         for ( i = 0; i < npts; i++ )
00375         {
00376             xscl[i] = x[i];
00377             yscl[i] = y[i];
00378         }
00379         difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
00380         plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma, grline );
00381     }
00382     else
00383     {
00384         grline( x, y, npts );
00385     }
00386 }
00387 
00388 // Draw polyline
00389 // The plot buffer must be called first
00390 
00391 void
00392 plP_polyline( short *x, short *y, PLINT npts )
00393 {
00394     PLINT i, clpxmi, clpxma, clpymi, clpyma;
00395 
00396     plsc->page_status = DRAWING;
00397 
00398     if ( plsc->plbuf_write )
00399         plbuf_polyline( plsc, x, y, npts );
00400 
00401     if ( plsc->difilt )
00402     {
00403         for ( i = 0; i < npts; i++ )
00404         {
00405             xscl[i] = x[i];
00406             yscl[i] = y[i];
00407         }
00408         difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
00409         plP_pllclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
00410             grpolyline );
00411     }
00412     else
00413     {
00414         grpolyline( x, y, npts );
00415     }
00416 }
00417 
00418 // Fill polygon
00419 // The plot buffer must be called first
00420 // Here if the desired area fill capability isn't present, we mock up
00421 // something in software
00422 
00423 static int foo;
00424 
00425 void
00426 plP_fill( short *x, short *y, PLINT npts )
00427 {
00428     PLINT i, clpxmi, clpxma, clpymi, clpyma;
00429 
00430     plsc->page_status = DRAWING;
00431 
00432     if ( plsc->plbuf_write )
00433     {
00434         plsc->dev_npts = npts;
00435         plsc->dev_x    = x;
00436         plsc->dev_y    = y;
00437         plbuf_esc( plsc, PLESC_FILL, NULL );
00438     }
00439 
00440 // Account for driver ability to do fills
00441 
00442     if ( plsc->patt == 0 && !plsc->dev_fill0 )
00443     {
00444         if ( !foo )
00445         {
00446             plwarn( "Driver does not support hardware solid fills, switching to software fill.\n" );
00447             foo = 1;
00448         }
00449         plsc->patt = 8;
00450         plpsty( plsc->patt );
00451     }
00452     if ( plsc->dev_fill1 )
00453     {
00454         plsc->patt = -ABS( plsc->patt );
00455     }
00456 
00457 // Perform fill.  Here we MUST NOT allow the software fill to pass through the
00458 // driver interface filtering twice, else we get the infamous 2*rotation for
00459 // software fills on orientation swaps.
00460 //
00461 
00462     if ( plsc->patt > 0 )
00463         plfill_soft( x, y, npts );
00464 
00465     else
00466     {
00467         if ( plsc->difilt )
00468         {
00469             for ( i = 0; i < npts; i++ )
00470             {
00471                 xscl[i] = x[i];
00472                 yscl[i] = y[i];
00473             }
00474             difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
00475             plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
00476                 grfill );
00477         }
00478         else
00479         {
00480             grfill( x, y, npts );
00481         }
00482     }
00483 }
00484 
00485 // Render a gradient
00486 // The plot buffer must be called first
00487 // N.B. plP_gradient is never called (see plgradient) unless the
00488 // device driver has set plsc->dev_gradient to true.
00489 
00490 void
00491 plP_gradient( short *x, short *y, PLINT npts )
00492 {
00493     PLINT i, clpxmi, clpxma, clpymi, clpyma;
00494 
00495     plsc->page_status = DRAWING;
00496 
00497     if ( plsc->plbuf_write )
00498     {
00499         plsc->dev_npts = npts;
00500         plsc->dev_x    = x;
00501         plsc->dev_y    = y;
00502         plbuf_esc( plsc, PLESC_GRADIENT, NULL );
00503     }
00504 
00505     // Render gradient with driver.
00506     if ( plsc->difilt )
00507     {
00508         for ( i = 0; i < npts; i++ )
00509         {
00510             xscl[i] = x[i];
00511             yscl[i] = y[i];
00512         }
00513         difilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
00514         plP_plfclp( xscl, yscl, npts, clpxmi, clpxma, clpymi, clpyma,
00515             grgradient );
00516     }
00517     else
00518     {
00519         grgradient( x, y, npts );
00520     }
00521 }
00522 
00523 // Account for driver ability to draw text itself
00524 //
00525 // #define DEBUG_TEXT
00526 //
00527 
00528 //--------------------------------------------------------------------------
00529 //  int text2num( char *text, char end, PLUNICODE *num)
00530 //       char *text - pointer to the text to be parsed
00531 //       char end   - end character (i.e. ')' or ']' to stop parsing
00532 //       PLUNICODE *num - pointer to an PLUNICODE to store the value
00533 //
00534 //    Function takes a string, which can be either hex or decimal,
00535 //    and converts it into an PLUNICODE, stopping at either a null,
00536 //    or the character pointed to by 'end'. This implementation using
00537 //    the C library strtoul replaces the original brain-dead version
00538 //    and should be more robust to invalid control strings.
00539 //--------------------------------------------------------------------------
00540 
00541 int text2num( const char *text, char end, PLUNICODE *num )
00542 {
00543     char *endptr;
00544     char msgbuf[BUFFER_SIZE];
00545 
00546     *num = (PLUNICODE) strtoul( text, &endptr, 0 );
00547 
00548     if ( end != endptr[0] )
00549     {
00550         snprintf( msgbuf, BUFFER_SIZE, "text2num: invalid control string detected - %c expected", end );
00551         plwarn( msgbuf );
00552     }
00553 
00554     return (int) ( endptr - text );
00555 }
00556 
00557 //--------------------------------------------------------------------------
00558 //  int text2fci( char *text, unsigned char *hexdigit, unsigned char *hexpower)
00559 //       char *text - pointer to the text to be parsed
00560 //       unsigned char *hexdigit - pointer to hex value that is stored.
00561 //       unsigned char *hexpower - pointer to hex power (left shift) that is stored.
00562 //
00563 //    Function takes a pointer to a string, which is looked up in a table
00564 //    to determine the corresponding FCI (font characterization integer)
00565 //    hex digit value and hex power (left shift).  All matched strings
00566 //    start with "<" and end with the two characters "/>".
00567 //    If the lookup succeeds, hexdigit and hexpower are set to the appropriate
00568 //    values in the table, and the function returns the number of characters
00569 //    in text that are consumed by the matching string in the table lookup.
00570 //
00571 //    If the lookup fails, hexdigit is set to 0, hexpower is set to and
00572 //    impossible value, and the function returns 0.
00573 //--------------------------------------------------------------------------
00574 
00575 int text2fci( const char *text, unsigned char *hexdigit, unsigned char *hexpower )
00576 {
00577     typedef struct
00578     {
00579         const char    *ptext;
00580         unsigned char hexdigit;
00581         unsigned char hexpower;
00582     }
00583     TextLookupTable;
00584     // This defines the various font control commands and the corresponding
00585     // hexdigit and hexpower in the FCI.
00586     //
00587 #define N_TextLookupTable    10
00588     const TextLookupTable lookup[N_TextLookupTable] = {
00589         { "<sans-serif/>", PL_FCI_SANS,    PL_FCI_FAMILY },
00590         { "<serif/>",      PL_FCI_SERIF,   PL_FCI_FAMILY },
00591         { "<monospace/>",  PL_FCI_MONO,    PL_FCI_FAMILY },
00592         { "<script/>",     PL_FCI_SCRIPT,  PL_FCI_FAMILY },
00593         { "<symbol/>",     PL_FCI_SYMBOL,  PL_FCI_FAMILY },
00594         { "<upright/>",    PL_FCI_UPRIGHT, PL_FCI_STYLE  },
00595         { "<italic/>",     PL_FCI_ITALIC,  PL_FCI_STYLE  },
00596         { "<oblique/>",    PL_FCI_OBLIQUE, PL_FCI_STYLE  },
00597         { "<medium/>",     PL_FCI_MEDIUM,  PL_FCI_WEIGHT },
00598         { "<bold/>",       PL_FCI_BOLD,    PL_FCI_WEIGHT }
00599     };
00600     int i, length;
00601     for ( i = 0; i < N_TextLookupTable; i++ )
00602     {
00603         length = (int) strlen( lookup[i].ptext );
00604         if ( !strncmp( text, lookup[i].ptext, (size_t) length ) )
00605         {
00606             *hexdigit = lookup[i].hexdigit;
00607             *hexpower = lookup[i].hexpower;
00608             return ( length );
00609         }
00610     }
00611     *hexdigit = 0;
00612     *hexpower = PL_FCI_HEXPOWER_IMPOSSIBLE;
00613     return ( 0 );
00614 }
00615 
00616 static PLUNICODE unicode_buffer[1024];
00617 
00618 void
00619 plP_text( PLINT base, PLFLT just, PLFLT *xform, PLINT x, PLINT y,
00620           PLINT refx, PLINT refy, const char *string )
00621 {
00622     if ( plsc->dev_text ) // Does the device render it's own text ?
00623     {
00624         EscText   args;
00625         short     len = 0;
00626         char      skip;
00627         int       i, j;
00628         PLUNICODE code;
00629         char      esc;
00630         int       idx = -1;
00631 
00632         args.base   = base;
00633         args.just   = just;
00634         args.xform  = xform;
00635         args.x      = x;
00636         args.y      = y;
00637         args.refx   = refx;
00638         args.refy   = refy;
00639         args.string = string;
00640 
00641         if ( plsc->dev_unicode ) // Does the device also understand unicode?
00642         {
00643             PLINT         ig;
00644             PLUNICODE     fci;
00645             PLUNICODE     orig_fci;
00646             unsigned char hexdigit, hexpower;
00647 
00648             // Now process the text string
00649 
00650             if ( string != NULL )   // If the string isn't blank, then we will
00651                                     // continue
00652                                     //
00653 
00654             {
00655                 len = (short) strlen( string ); // this length is only used in the loop
00656                 // counter, we will work out the length of
00657                 // the unicode string as we go
00658                 plgesc( &esc );
00659 
00660                 // At this stage we will do some translations into unicode, like
00661                 // conversion to Greek , and will save other translations such as
00662                 // superscript for the driver to do later on. As we move through
00663                 // the string and do the translations, we will get
00664                 // rid of the esc character sequence, just replacing it with
00665                 // unicode.
00666                 //
00667 
00668                 // Obtain FCI (font characterization integer) for start of
00669                 // string.
00670                 plgfci( &fci );
00671                 orig_fci = fci;
00672 
00673                 // Walk through the string, and convert
00674                 // some stuff to unicode on the fly
00675                 for ( j = i = 0; i < len; i++ )
00676                 {
00677                     skip = 0;
00678 
00679                     if ( string[i] == esc )
00680                     {
00681                         switch ( string[i + 1] )
00682                         {
00683                         case '(': // hershey code
00684                             i  += ( 2 + text2num( &string[i + 2], ')', &code ) );
00685                             idx = plhershey2unicode( (int) code );
00686                             unicode_buffer[j++] = \
00687                                 (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode;
00688 
00689 
00690                             // if unicode_buffer[j-1] corresponds to the escape
00691                             // character must unescape it by appending one more.
00692                             // This will probably always be necessary since it is
00693                             // likely unicode_buffer will always have to contain
00694                             // escape characters that are interpreted by the device
00695                             // driver.
00696                             //
00697                             if ( unicode_buffer[j - 1] == (PLUNICODE) esc )
00698                                 unicode_buffer[j++] = (PLUNICODE) esc;
00699                             j--;
00700                             skip = 1;
00701                             break;
00702 
00703                         case '[': // unicode
00704                             i += ( 2 + text2num( &string[i + 2], ']', &code ) );
00705                             unicode_buffer[j++] = code;
00706 
00707 
00708                             // if unicode_buffer[j-1] corresponds to the escape
00709                             // character must unescape it by appending one more.
00710                             // This will probably always be necessary since it is
00711                             // likely unicode_buffer will always have to contain
00712                             // escape characters that are interpreted by the device
00713                             // driver.
00714                             //
00715                             if ( unicode_buffer[j - 1] == (PLUNICODE) esc )
00716                                 unicode_buffer[j++] = (PLUNICODE) esc;
00717                             j--;
00718                             skip = 1;
00719                             break;
00720 
00721                         case '<': // change font
00722                             if ( '0' <= string[i + 2] && string[i + 2] <= '9' )
00723                             {
00724                                 i += 2 + text2num( &string[i + 2], '>', &code );
00725                                 if ( code & PL_FCI_MARK )
00726                                 {
00727                                     // code is a complete FCI (font characterization
00728                                     // integer): change FCI to this value.
00729                                     //
00730                                     fci = code;
00731                                     unicode_buffer[j] = fci;
00732                                     skip = 1;
00733                                 }
00734                                 else
00735                                 {
00736                                     // code is not complete FCI. Change
00737                                     // FCI with hex power in rightmost hex
00738                                     // digit and hex digit value in second rightmost
00739                                     // hex digit.
00740                                     //
00741                                     hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK;
00742                                     hexpower = code & PL_FCI_HEXPOWER_MASK;
00743                                     plP_hex2fci( hexdigit, hexpower, &fci );
00744                                     unicode_buffer[j] = fci;
00745                                     skip = 1;
00746                                 }
00747                             }
00748                             else
00749                             {
00750                                 i += text2fci( &string[i + 1], &hexdigit, &hexpower );
00751                                 if ( hexpower < 7 )
00752                                 {
00753                                     plP_hex2fci( hexdigit, hexpower, &fci );
00754                                     unicode_buffer[j] = fci;
00755                                     skip = 1;
00756                                 }
00757                             }
00758                             break;
00759 
00760                         case 'f': // Deprecated Hershey-style font change
00761                         case 'F': // Deprecated Hershey-style font change
00762                             // We implement an approximate response here so that
00763                             // reasonable results are obtained for unicode fonts,
00764                             // but this method is deprecated and the #<nnn> or
00765                             // #<command string> methods should be used instead
00766                             // to change unicode fonts in mid-string.
00767                             //
00768                             fci = PL_FCI_MARK;
00769                             if ( string[i + 2] == 'n' )
00770                             {
00771                                 // medium, upright, sans-serif
00772                                 plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci );
00773                             }
00774                             else if ( string[i + 2] == 'r' )
00775                             {
00776                                 // medium, upright, serif
00777                                 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
00778                             }
00779                             else if ( string[i + 2] == 'i' )
00780                             {
00781                                 // medium, italic, serif
00782                                 plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci );
00783                                 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
00784                             }
00785                             else if ( string[i + 2] == 's' )
00786                             {
00787                                 // medium, upright, script
00788                                 plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci );
00789                             }
00790                             else
00791                                 fci = PL_FCI_IMPOSSIBLE;
00792 
00793                             if ( fci != PL_FCI_IMPOSSIBLE )
00794                             {
00795                                 i += 2;
00796                                 unicode_buffer[j] = fci;
00797                                 skip = 1;
00798                             }
00799                             break;
00800 
00801                         case 'g': // Greek font
00802                         case 'G': // Greek font
00803                             // Get the index in the lookup table
00804                             // 527 = upper case alpha displacement in Hershey Table
00805                             // 627 = lower case alpha displacement in Hershey Table
00806                             //
00807 
00808                             ig = plP_strpos( plP_greek_mnemonic, string[i + 2] );
00809                             if ( ig >= 0 )
00810                             {
00811                                 if ( ig >= 24 )
00812                                     ig = ig + 100 - 24;
00813                                 ig = ig + 527;
00814                                 // Follow pldeco in plsym.c which for
00815                                 // lower case epsilon, theta, and phi
00816                                 // substitutes (684, 685, and 686) for
00817                                 // (631, 634, and 647)
00818                                 if ( ig == 631 )
00819                                     ig = 684;
00820                                 else if ( ig == 634 )
00821                                     ig = 685;
00822                                 else if ( ig == 647 )
00823                                     ig = 686;
00824                                 idx = (int) plhershey2unicode( ig );
00825                                 unicode_buffer[j++] = \
00826                                     (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode;
00827                                 i   += 2;
00828                                 skip = 1; // skip is set if we have copied something
00829                                           // into the unicode table
00830                             }
00831                             else
00832                             {
00833                                 // Use "unknown" unicode character if string[i+2]
00834                                 // is not in the Greek array.
00835                                 unicode_buffer[j++] = (PLUNICODE) 0x00;
00836                                 i   += 2;
00837                                 skip = 1;                // skip is set if we have copied something
00838                                                          // into  the unicode table
00839                             }
00840                             j--;
00841                             break;
00842                         }
00843                     }
00844 
00845                     if ( skip == 0 )
00846                     {
00847                         PLUNICODE  unichar = 0;
00848 #ifdef HAVE_LIBUNICODE
00849                         const char * ptr = unicode_get_utf8( string + i, &unichar );
00850 #else
00851                         const char * ptr = utf8_to_ucs4( string + i, &unichar );
00852 #endif
00853                         if ( ptr == NULL )
00854                         {
00855                             char buf[BUFFER_SIZE];
00856                             char tmpstring[31];
00857                             strncpy( tmpstring, string, 30 );
00858                             tmpstring[30] = '\0';
00859                             snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
00860                                 tmpstring, strlen( string ) > 30 ? "[...]" : "" );
00861                             plabort( buf );
00862                             return;
00863                         }
00864                         unicode_buffer [j] = unichar;
00865                         i += (int) ( ptr - ( string + i ) - 1 );
00866 
00867                         // Search for escesc (an unescaped escape) in the input
00868                         // string and adjust unicode_buffer accordingly).
00869                         //
00870                         if ( unicode_buffer[j] == (PLUNICODE) esc && string[i + 1] == esc )
00871                         {
00872                             i++;
00873                             unicode_buffer[++j] = (PLUNICODE) esc;
00874                         }
00875                     }
00876                     j++;
00877                 }
00878                 if ( j > 0 )
00879                 {
00880                     args.unicode_array_len = (short unsigned int) j; // Much easier to set the length than
00881                     // work it out later :-)
00882                     args.unicode_array = &unicode_buffer[0];         // Get address of the
00883                                                                      // unicode buffer (even
00884                                                                      // though it is
00885                                                                      // currently  static)
00886                 }
00887 
00888 
00889                 // The alternate unicode text handling loop.
00890 
00891                 if ( plsc->alt_unicode )
00892                 {
00893                     args.n_fci = orig_fci;
00894                     plP_esc( PLESC_BEGIN_TEXT, &args );
00895 
00896                     for ( i = 0; i < len; i++ )
00897                     {
00898                         skip = 0;
00899 
00900                         if ( string[i] == esc )
00901                         {
00902                             switch ( string[i + 1] )
00903                             {
00904                             case '(': // hershey code
00905                                 i          += 2 + text2num( &string[i + 2], ')', &code );
00906                                 idx         = plhershey2unicode( (int) code );
00907                                 args.n_char = \
00908                                     (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode;
00909                                 plP_esc( PLESC_TEXT_CHAR, &args );
00910 
00911                                 skip = 1;
00912                                 break;
00913 
00914                             case '[': // unicode
00915                                 i          += 2 + text2num( &string[i + 2], ']', &code );
00916                                 args.n_char = code;
00917                                 plP_esc( PLESC_TEXT_CHAR, &args );
00918                                 skip = 1;
00919                                 break;
00920 
00921                             case '<': // change font
00922                                 if ( '0' <= string[i + 2] && string[i + 2] <= '9' )
00923                                 {
00924                                     i += 2 + text2num( &string[i + 2], '>', &code );
00925                                     if ( code & PL_FCI_MARK )
00926                                     {
00927                                         // code is a complete FCI (font characterization
00928                                         // integer): change FCI to this value.
00929                                         //
00930                                         fci  = code;
00931                                         skip = 1;
00932 
00933                                         args.n_fci       = fci;
00934                                         args.n_ctrl_char = PLTEXT_FONTCHANGE;
00935                                         plP_esc( PLESC_CONTROL_CHAR, &args );
00936                                     }
00937                                     else
00938                                     {
00939                                         // code is not complete FCI. Change
00940                                         // FCI with hex power in rightmost hex
00941                                         // digit and hex digit value in second rightmost
00942                                         // hex digit.
00943                                         //
00944                                         hexdigit = ( code >> 4 ) & PL_FCI_HEXDIGIT_MASK;
00945                                         hexpower = code & PL_FCI_HEXPOWER_MASK;
00946                                         plP_hex2fci( hexdigit, hexpower, &fci );
00947                                         skip = 1;
00948 
00949                                         args.n_fci       = fci;
00950                                         args.n_ctrl_char = PLTEXT_FONTCHANGE;
00951                                         plP_esc( PLESC_CONTROL_CHAR, &args );
00952                                     }
00953                                 }
00954                                 else
00955                                 {
00956                                     i += text2fci( &string[i + 1], &hexdigit, &hexpower );
00957                                     if ( hexpower < 7 )
00958                                     {
00959                                         plP_hex2fci( hexdigit, hexpower, &fci );
00960                                         skip = 1;
00961 
00962                                         args.n_fci       = fci;
00963                                         args.n_ctrl_char = PLTEXT_FONTCHANGE;
00964                                         plP_esc( PLESC_CONTROL_CHAR, &args );
00965                                     }
00966                                 }
00967                                 break;
00968 
00969                             case 'f': // Deprecated Hershey-style font change
00970                             case 'F': // Deprecated Hershey-style font change
00971                                 // We implement an approximate response here so that
00972                                 // reasonable results are obtained for unicode fonts,
00973                                 // but this method is deprecated and the #<nnn> or
00974                                 // #<command string> methods should be used instead
00975                                 // to change unicode fonts in mid-string.
00976                                 //
00977                                 fci = PL_FCI_MARK;
00978                                 if ( string[i + 2] == 'n' )
00979                                 {
00980                                     // medium, upright, sans-serif
00981                                     plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci );
00982                                 }
00983                                 else if ( string[i + 2] == 'r' )
00984                                 {
00985                                     // medium, upright, serif
00986                                     plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
00987                                 }
00988                                 else if ( string[i + 2] == 'i' )
00989                                 {
00990                                     // medium, italic, serif
00991                                     plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci );
00992                                     plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
00993                                 }
00994                                 else if ( string[i + 2] == 's' )
00995                                 {
00996                                     // medium, upright, script
00997                                     plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci );
00998                                 }
00999                                 else
01000                                     fci = PL_FCI_IMPOSSIBLE;
01001 
01002                                 if ( fci != PL_FCI_IMPOSSIBLE )
01003                                 {
01004                                     i   += 2;
01005                                     skip = 1;
01006 
01007                                     args.n_fci       = fci;
01008                                     args.n_ctrl_char = PLTEXT_FONTCHANGE;
01009                                     plP_esc( PLESC_CONTROL_CHAR, &args );
01010                                 }
01011                                 break;
01012 
01013                             case 'g': // Greek font
01014                             case 'G': // Greek font
01015                                 // Get the index in the lookup table
01016                                 // 527 = upper case alpha displacement in Hershey Table
01017                                 // 627 = lower case alpha displacement in Hershey Table
01018                                 //
01019                                 ig = plP_strpos( plP_greek_mnemonic, string[i + 2] );
01020                                 if ( ig >= 0 )
01021                                 {
01022                                     if ( ig >= 24 )
01023                                         ig = ig + 100 - 24;
01024                                     ig = ig + 527;
01025                                     // Follow pldeco in plsym.c which for
01026                                     // lower case epsilon, theta, and phi
01027                                     // substitutes (684, 685, and 686) for
01028                                     // (631, 634, and 647)
01029                                     if ( ig == 631 )
01030                                         ig = 684;
01031                                     else if ( ig == 634 )
01032                                         ig = 685;
01033                                     else if ( ig == 647 )
01034                                         ig = 686;
01035                                     idx  = plhershey2unicode( ig );
01036                                     i   += 2;
01037                                     skip = 1; // skip is set if we have copied something
01038                                               // into the unicode table
01039 
01040                                     args.n_char = \
01041                                         (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode;
01042                                     plP_esc( PLESC_TEXT_CHAR, &args );
01043                                 }
01044                                 else
01045                                 {
01046                                     // Use "unknown" unicode character if string[i+2]
01047                                     // is not in the Greek array.
01048                                     i   += 2;
01049                                     skip = 1;            // skip is set if we have copied something
01050                                                          // into  the unicode table
01051 
01052                                     args.n_char = \
01053                                         (PLUNICODE) hershey_to_unicode_lookup_table[idx].Unicode;
01054                                     plP_esc( PLESC_TEXT_CHAR, &args );
01055                                 }
01056                                 break;
01057 
01058                             case 'u':
01059                                 args.n_ctrl_char = PLTEXT_SUPERSCRIPT;
01060                                 plP_esc( PLESC_CONTROL_CHAR, &args );
01061                                 i   += 1;
01062                                 skip = 1;
01063                                 break;
01064 
01065                             case 'd':
01066                                 args.n_ctrl_char = PLTEXT_SUBSCRIPT;
01067                                 plP_esc( PLESC_CONTROL_CHAR, &args );
01068                                 i   += 1;
01069                                 skip = 1;
01070                                 break;
01071                             case 'b':
01072                                 args.n_ctrl_char = PLTEXT_BACKCHAR;
01073                                 plP_esc( PLESC_CONTROL_CHAR, &args );
01074                                 i   += 1;
01075                                 skip = 1;
01076                                 break;
01077                             case '+':
01078                                 args.n_ctrl_char = PLTEXT_OVERLINE;
01079                                 plP_esc( PLESC_CONTROL_CHAR, &args );
01080                                 i   += 1;
01081                                 skip = 1;
01082                                 break;
01083                             case '-':
01084                                 args.n_ctrl_char = PLTEXT_UNDERLINE;
01085                                 plP_esc( PLESC_CONTROL_CHAR, &args );
01086                                 i   += 1;
01087                                 skip = 1;
01088                                 break;
01089                             }
01090                         }
01091 
01092                         if ( skip == 0 )
01093                         {
01094                             PLUNICODE  unichar = 0;
01095 #ifdef HAVE_LIBUNICODE
01096                             const char * ptr = unicode_get_utf8( string + i, &unichar );
01097 #else
01098                             const char * ptr = utf8_to_ucs4( string + i, &unichar );
01099 #endif
01100                             if ( ptr == NULL )
01101                             {
01102                                 char buf[BUFFER_SIZE];
01103                                 char tmpstring[31];
01104                                 strncpy( tmpstring, string, 30 );
01105                                 tmpstring[30] = '\0';
01106                                 snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
01107                                     tmpstring, strlen( string ) > 30 ? "[...]" : "" );
01108                                 plabort( buf );
01109                                 return;
01110                             }
01111                             i += (int) ( ptr - ( string + i ) - 1 );
01112 
01113                             // Search for escesc (an unescaped escape) in the input
01114                             // string and adjust unicode_buffer accordingly).
01115                             //
01116                             if ( string[i] == esc && string[i + 1] == esc )
01117                             {
01118                                 i++;
01119                                 args.n_char = (PLUNICODE) esc;
01120                             }
01121                             else
01122                             {
01123                                 args.n_char = unichar;
01124                             }
01125                             plP_esc( PLESC_TEXT_CHAR, &args );
01126                         }
01127                     }
01128                     plP_esc( PLESC_END_TEXT, &args );
01129                 }
01130 
01131                 // No text to display
01132 
01133                 if ( j == 0 )
01134                     return;
01135             }
01136         }
01137 
01138         if ( plsc->dev_unicode )
01139         {
01140             args.string = NULL; // We are using unicode
01141         }
01142         else
01143         {
01144             args.string = string;
01145         }
01146 
01147         plP_esc( PLESC_HAS_TEXT, &args );
01148 
01149 #ifndef DEBUG_TEXT
01150     }
01151     else
01152     {
01153 #endif
01154         plstr( base, xform, refx, refy, string );
01155     }
01156 }
01157 
01158 // convert utf8 string to ucs4 unichar
01159 static const char *
01160 utf8_to_ucs4( const char *ptr, PLUNICODE *unichar )
01161 {
01162     char tmp;
01163     int  isFirst = 1;
01164     int  cnt     = 0;
01165 
01166     do
01167     {
01168         // Get next character in string
01169         tmp = *ptr++;
01170         if ( isFirst ) // First char in UTF8 sequence
01171         {
01172             isFirst = 0;
01173             // Determine length of sequence
01174             if ( (unsigned char) ( tmp & 0x80 ) == 0x00 ) // single char
01175             {
01176                 *unichar = (unsigned int) tmp & 0x7F;
01177                 cnt      = 0;
01178             }
01179             else if ( (unsigned char) ( tmp & 0xE0 ) == 0xC0 ) // 2 chars
01180             {
01181                 *unichar = (unsigned int) tmp & 0x1F;
01182                 cnt      = 1;
01183             }
01184             else if ( (unsigned char) ( tmp & 0xF0 ) == 0xE0 ) // 3 chars
01185             {
01186                 *unichar = (unsigned char) tmp & 0x0F;
01187                 cnt      = 2;
01188             }
01189             else if ( (unsigned char) ( tmp & 0xF8 ) == 0xF0 ) // 4 chars
01190             {
01191                 *unichar = (unsigned char) tmp & 0x07;
01192                 cnt      = 3;
01193             }
01194             else if ( (unsigned char) ( tmp & 0xFC ) == 0xF8 ) // 5 chars
01195             {
01196                 *unichar = (unsigned char) tmp & 0x03;
01197                 cnt      = 4;
01198             }
01199             else if ( (unsigned char) ( tmp & 0xFE ) == 0xFC ) // 6 chars
01200             {
01201                 *unichar = (unsigned char) tmp & 0x01;
01202                 cnt      = 5;
01203             }
01204             else  // Malformed
01205             {
01206                 ptr = NULL;
01207                 cnt = 0;
01208             }
01209         }
01210         else   // Subsequent char in UTF8 sequence
01211         {
01212             if ( (unsigned char) ( tmp & 0xC0 ) == 0x80 )
01213             {
01214                 *unichar = ( *unichar << 6 ) | ( (unsigned int) tmp & 0x3F );
01215                 cnt--;
01216             }
01217             else  // Malformed
01218             {
01219                 ptr = NULL;
01220                 cnt = 0;
01221             }
01222         }
01223     } while ( cnt > 0 );
01224     return ptr;
01225 }
01226 
01227 // convert ucs4 unichar to utf8 string
01228 int
01229 ucs4_to_utf8( PLUNICODE unichar, char *ptr )
01230 {
01231     unsigned char *tmp;
01232     int           len;
01233 
01234     tmp = (unsigned char *) ptr;
01235 
01236     if ( ( unichar & 0xffff80 ) == 0 ) // single byte
01237     {
01238         *tmp = (unsigned char) unichar;
01239         tmp++;
01240         len = 1;
01241     }
01242     else if ( ( unichar & 0xfff800 ) == 0 ) // two bytes
01243     {
01244         *tmp = (unsigned char) 0xc0 | (unsigned char) ( unichar >> 6 );
01245         tmp++;
01246         *tmp = (unsigned char) ( 0x80 | (unsigned char) ( unichar & (PLUINT) 0x3f ) );
01247         tmp++;
01248         len = 2;
01249     }
01250     else if ( ( unichar & 0xff0000 ) == 0 ) // three bytes
01251     {
01252         *tmp = (unsigned char) 0xe0 | (unsigned char) ( unichar >> 12 );
01253         tmp++;
01254         *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 6 ) & 0x3f ) );
01255         tmp++;
01256         *tmp = (unsigned char) ( 0x80 | ( (unsigned char) unichar & 0x3f ) );
01257         tmp++;
01258         len = 3;
01259     }
01260     else if ( ( unichar & 0xe0000 ) == 0 ) // four bytes
01261     {
01262         *tmp = (unsigned char) 0xf0 | (unsigned char) ( unichar >> 18 );
01263         tmp++;
01264         *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 12 ) & 0x3f ) );
01265         tmp++;
01266         *tmp = (unsigned char) ( 0x80 | (unsigned char) ( ( unichar >> 6 ) & 0x3f ) );
01267         tmp++;
01268         *tmp = (unsigned char) ( 0x80 | (unsigned char) ( unichar & 0x3f ) );
01269         tmp++;
01270         len = 4;
01271     }
01272     else  // Illegal coding
01273     {
01274         len = 0;
01275     }
01276     *tmp = '\0';
01277 
01278     return len;
01279 }
01280 
01281 static void
01282 grline( short *x, short *y, PLINT PL_UNUSED( npts ) )
01283 {
01284     char *save_locale = plsave_set_locale();
01285     if ( !plsc->stream_closed )
01286     {
01287         ( *plsc->dispatch_table->pl_line )( (struct PLStream_struct *) plsc,
01288             x[0], y[0], x[1], y[1] );
01289     }
01290     plrestore_locale( save_locale );
01291 }
01292 
01293 static void
01294 grpolyline( short *x, short *y, PLINT npts )
01295 {
01296     char *save_locale = plsave_set_locale();
01297     if ( !plsc->stream_closed )
01298     {
01299         ( *plsc->dispatch_table->pl_polyline )( (struct PLStream_struct *) plsc,
01300             x, y, npts );
01301     }
01302     plrestore_locale( save_locale );
01303 }
01304 
01305 static void
01306 grfill( short *x, short *y, PLINT npts )
01307 {
01308     char * save_locale;
01309     plsc->dev_npts = npts;
01310     plsc->dev_x    = x;
01311     plsc->dev_y    = y;
01312 
01313     save_locale = plsave_set_locale();
01314     if ( !plsc->stream_closed )
01315     {
01316         ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
01317             PLESC_FILL, NULL );
01318     }
01319     plrestore_locale( save_locale );
01320 }
01321 
01322 static void
01323 grgradient( short *x, short *y, PLINT npts )
01324 {
01325     char * save_locale;
01326     plsc->dev_npts = npts;
01327     plsc->dev_x    = x;
01328     plsc->dev_y    = y;
01329 
01330     save_locale = plsave_set_locale();
01331     if ( !plsc->stream_closed )
01332     {
01333         ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
01334             PLESC_GRADIENT, NULL );
01335     }
01336     plrestore_locale( save_locale );
01337 }
01338 
01339 //--------------------------------------------------------------------------
01340 // void difilt
01341 //
01342 // Driver interface filter -- passes all coordinates through a variety
01343 // of filters.  These include filters to change :
01344 //
01345 //      - mapping of meta to physical coordinates
01346 //      - plot orientation
01347 //      - window into plot (zooms)
01348 //      - window into device (i.e set margins)
01349 //
01350 // The filters are applied in the order specified above.  Because the
01351 // orientation change comes first, subsequent window specifications affect
01352 // the new coordinates (i.e. after a 90 degree flip, what was x is now y).
01353 // This is the only way that makes sense from a graphical interface
01354 // (e.g. TCL/TK driver).
01355 //
01356 // Where appropriate, the page clip limits are modified.
01357 //--------------------------------------------------------------------------
01358 
01359 void
01360 difilt( PLINT *xsc, PLINT *ysc, PLINT npts,
01361         PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma )
01362 {
01363     PLINT i, x, y;
01364 
01365 // Map meta coordinates to physical coordinates
01366 
01367     if ( plsc->difilt & PLDI_MAP )
01368     {
01369         for ( i = 0; i < npts; i++ )
01370         {
01371             xsc[i] = (PLINT) ( plsc->dimxax * xsc[i] + plsc->dimxb );
01372             ysc[i] = (PLINT) ( plsc->dimyay * ysc[i] + plsc->dimyb );
01373         }
01374     }
01375 
01376 // Change orientation
01377 
01378     if ( plsc->difilt & PLDI_ORI )
01379     {
01380         for ( i = 0; i < npts; i++ )
01381         {
01382             x      = (PLINT) ( plsc->dioxax * xsc[i] + plsc->dioxay * ysc[i] + plsc->dioxb );
01383             y      = (PLINT) ( plsc->dioyax * xsc[i] + plsc->dioyay * ysc[i] + plsc->dioyb );
01384             xsc[i] = x;
01385             ysc[i] = y;
01386         }
01387     }
01388 
01389 // Change window into plot space
01390 
01391     if ( plsc->difilt & PLDI_PLT )
01392     {
01393         for ( i = 0; i < npts; i++ )
01394         {
01395             xsc[i] = (PLINT) ( plsc->dipxax * xsc[i] + plsc->dipxb );
01396             ysc[i] = (PLINT) ( plsc->dipyay * ysc[i] + plsc->dipyb );
01397         }
01398     }
01399 
01400 // Change window into device space and set clip limits
01401 // (this is the only filter that modifies them)
01402 
01403     if ( plsc->difilt & PLDI_DEV )
01404     {
01405         for ( i = 0; i < npts; i++ )
01406         {
01407             xsc[i] = (PLINT) ( plsc->didxax * xsc[i] + plsc->didxb );
01408             ysc[i] = (PLINT) ( plsc->didyay * ysc[i] + plsc->didyb );
01409         }
01410         *clpxmi = plsc->diclpxmi;
01411         *clpxma = plsc->diclpxma;
01412         *clpymi = plsc->diclpymi;
01413         *clpyma = plsc->diclpyma;
01414     }
01415     else
01416     {
01417         *clpxmi = plsc->phyxmi;
01418         *clpxma = plsc->phyxma;
01419         *clpymi = plsc->phyymi;
01420         *clpyma = plsc->phyyma;
01421     }
01422 }
01423 
01424 
01425 // Function is unused except for commented out image code
01426 // If / when that is fixed, then reinstate this function.
01427 // Needs a prototype and the casting fixed.
01428 //
01429 // void
01430 // sdifilt( short *xscl, short *yscl, PLINT npts,
01431 //          PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma )
01432 // {
01433 //     int   i;
01434 //     short x, y;
01435 
01436 // // Map meta coordinates to physical coordinates
01437 
01438 //     if ( plsc->difilt & PLDI_MAP )
01439 //     {
01440 //         for ( i = 0; i < npts; i++ )
01441 //         {
01442 //             xscl[i] = (PLINT) ( plsc->dimxax * xscl[i] + plsc->dimxb );
01443 //             yscl[i] = (PLINT) ( plsc->dimyay * yscl[i] + plsc->dimyb );
01444 //         }
01445 //     }
01446 
01447 // // Change orientation
01448 
01449 //     if ( plsc->difilt & PLDI_ORI )
01450 //     {
01451 //         for ( i = 0; i < npts; i++ )
01452 //         {
01453 //             x       = (PLINT) ( plsc->dioxax * xscl[i] + plsc->dioxay * yscl[i] + plsc->dioxb );
01454 //             y       = (PLINT) ( plsc->dioyax * xscl[i] + plsc->dioyay * yscl[i] + plsc->dioyb );
01455 //             xscl[i] = x;
01456 //             yscl[i] = y;
01457 //         }
01458 //     }
01459 
01460 // // Change window into plot space
01461 
01462 //     if ( plsc->difilt & PLDI_PLT )
01463 //     {
01464 //         for ( i = 0; i < npts; i++ )
01465 //         {
01466 //             xscl[i] = (PLINT) ( plsc->dipxax * xscl[i] + plsc->dipxb );
01467 //             yscl[i] = (PLINT) ( plsc->dipyay * yscl[i] + plsc->dipyb );
01468 //         }
01469 //     }
01470 
01471 // // Change window into device space and set clip limits
01472 // // (this is the only filter that modifies them)
01473 
01474 //     if ( plsc->difilt & PLDI_DEV )
01475 //     {
01476 //         for ( i = 0; i < npts; i++ )
01477 //         {
01478 //             xscl[i] = (PLINT) ( plsc->didxax * xscl[i] + plsc->didxb );
01479 //             yscl[i] = (PLINT) ( plsc->didyay * yscl[i] + plsc->didyb );
01480 //         }
01481 //         *clpxmi = (PLINT) ( plsc->diclpxmi );
01482 //         *clpxma = (PLINT) ( plsc->diclpxma );
01483 //         *clpymi = (PLINT) ( plsc->diclpymi );
01484 //         *clpyma = (PLINT) ( plsc->diclpyma );
01485 //     }
01486 //     else
01487 //     {
01488 //         *clpxmi = plsc->phyxmi;
01489 //         *clpxma = plsc->phyxma;
01490 //         *clpymi = plsc->phyymi;
01491 //         *clpyma = plsc->phyyma;
01492 //     }
01493 // }
01494 
01495 //--------------------------------------------------------------------------
01496 // void difilt_clip
01497 //
01498 // This provides the transformed text clipping region for the benefit of
01499 // those drivers that render their own text.
01500 //--------------------------------------------------------------------------
01501 
01502 void
01503 difilt_clip( PLINT *x_coords, PLINT *y_coords )
01504 {
01505     PLINT x1c, x2c, y1c, y2c;
01506 
01507     x1c         = plsc->clpxmi;
01508     y1c         = plsc->clpymi;
01509     x2c         = plsc->clpxma;
01510     y2c         = plsc->clpyma;
01511     x_coords[0] = x1c;
01512     x_coords[1] = x1c;
01513     x_coords[2] = x2c;
01514     x_coords[3] = x2c;
01515     y_coords[0] = y1c;
01516     y_coords[1] = y2c;
01517     y_coords[2] = y2c;
01518     y_coords[3] = y1c;
01519     difilt( x_coords, y_coords, 4, &x1c, &x2c, &y1c, &y2c );
01520 }
01521 
01522 
01523 //--------------------------------------------------------------------------
01524 // void pldi_ini
01525 //
01526 // Updates driver interface, making sure everything is in order.
01527 // Even if filter is not being used, the defaults need to be set up.
01528 //--------------------------------------------------------------------------
01529 
01530 static void
01531 setdef_diplt( void )
01532 {
01533     plsc->dipxmin = 0.0;
01534     plsc->dipxmax = 1.0;
01535     plsc->dipymin = 0.0;
01536     plsc->dipymax = 1.0;
01537 }
01538 
01539 static void
01540 setdef_didev( void )
01541 {
01542     plsc->mar    = 0.0;
01543     plsc->aspect = 0.0;
01544     plsc->jx     = 0.0;
01545     plsc->jy     = 0.0;
01546 }
01547 
01548 static void
01549 setdef_diori( void )
01550 {
01551     plsc->diorot = 0.;
01552 }
01553 
01554 static void
01555 pldi_ini( void )
01556 {
01557     if ( plsc->level >= 1 )
01558     {
01559         if ( plsc->difilt & PLDI_MAP )  // Coordinate mapping
01560             calc_dimap();
01561 
01562         if ( plsc->difilt & PLDI_ORI )  // Orientation
01563             calc_diori();
01564         else
01565             setdef_diori();
01566 
01567         if ( plsc->difilt & PLDI_PLT )  // Plot window
01568             calc_diplt();
01569         else
01570             setdef_diplt();
01571 
01572         if ( plsc->difilt & PLDI_DEV )  // Device window
01573             calc_didev();
01574         else
01575             setdef_didev();
01576     }
01577 }
01578 
01579 //--------------------------------------------------------------------------
01580 // void pldid2pc
01581 //
01582 // Converts input values from relative device coordinates to relative plot
01583 // coordinates.  This function must be called when selecting a plot window
01584 // from a display driver, since the coordinates chosen by the user are
01585 // necessarily device-specific.
01586 //--------------------------------------------------------------------------
01587 
01588 void
01589 pldid2pc( PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax )
01590 {
01591     PLFLT pxmin, pymin, pxmax, pymax;
01592     PLFLT sxmin, symin, sxmax, symax;
01593     PLFLT rxmin, rymin, rxmax, rymax;
01594 
01595     if ( plsc->difilt & PLDI_DEV )
01596     {
01597         pldebug( "pldid2pc",
01598             "Relative device coordinates (in): %f, %f, %f, %f\n",
01599             *xmin, *ymin, *xmax, *ymax );
01600 
01601         pxmin = plP_dcpcx( *xmin );
01602         pymin = plP_dcpcy( *ymin );
01603         pxmax = plP_dcpcx( *xmax );
01604         pymax = plP_dcpcy( *ymax );
01605 
01606         sxmin = ( pxmin - plsc->didxb ) / plsc->didxax;
01607         symin = ( pymin - plsc->didyb ) / plsc->didyay;
01608         sxmax = ( pxmax - plsc->didxb ) / plsc->didxax;
01609         symax = ( pymax - plsc->didyb ) / plsc->didyay;
01610 
01611         rxmin = plP_pcdcx( (PLINT) sxmin );
01612         rymin = plP_pcdcy( (PLINT) symin );
01613         rxmax = plP_pcdcx( (PLINT) sxmax );
01614         rymax = plP_pcdcy( (PLINT) symax );
01615 
01616         *xmin = ( rxmin < 0 ) ? 0 : rxmin;
01617         *xmax = ( rxmax > 1 ) ? 1 : rxmax;
01618         *ymin = ( rymin < 0 ) ? 0 : rymin;
01619         *ymax = ( rymax > 1 ) ? 1 : rymax;
01620 
01621         pldebug( "pldid2pc",
01622             "Relative plot coordinates (out): %f, %f, %f, %f\n",
01623             rxmin, rymin, rxmax, rymax );
01624     }
01625 }
01626 
01627 //--------------------------------------------------------------------------
01628 // void pldip2dc
01629 //
01630 // Converts input values from relative plot coordinates to relative
01631 // device coordinates.
01632 //--------------------------------------------------------------------------
01633 
01634 void
01635 pldip2dc( PLFLT *xmin, PLFLT *ymin, PLFLT *xmax, PLFLT *ymax )
01636 {
01637     PLFLT pxmin, pymin, pxmax, pymax;
01638     PLFLT sxmin, symin, sxmax, symax;
01639     PLFLT rxmin, rymin, rxmax, rymax;
01640 
01641     if ( plsc->difilt & PLDI_DEV )
01642     {
01643         pldebug( "pldip2pc",
01644             "Relative plot coordinates (in): %f, %f, %f, %f\n",
01645             *xmin, *ymin, *xmax, *ymax );
01646 
01647         pxmin = plP_dcpcx( *xmin );
01648         pymin = plP_dcpcy( *ymin );
01649         pxmax = plP_dcpcx( *xmax );
01650         pymax = plP_dcpcy( *ymax );
01651 
01652         sxmin = pxmin * plsc->didxax + plsc->didxb;
01653         symin = pymin * plsc->didyay + plsc->didyb;
01654         sxmax = pxmax * plsc->didxax + plsc->didxb;
01655         symax = pymax * plsc->didyay + plsc->didyb;
01656 
01657         rxmin = plP_pcdcx( (PLINT) sxmin );
01658         rymin = plP_pcdcy( (PLINT) symin );
01659         rxmax = plP_pcdcx( (PLINT) sxmax );
01660         rymax = plP_pcdcy( (PLINT) symax );
01661 
01662         *xmin = ( rxmin < 0 ) ? 0 : rxmin;
01663         *xmax = ( rxmax > 1 ) ? 1 : rxmax;
01664         *ymin = ( rymin < 0 ) ? 0 : rymin;
01665         *ymax = ( rymax > 1 ) ? 1 : rymax;
01666 
01667         pldebug( "pldip2pc",
01668             "Relative device coordinates (out): %f, %f, %f, %f\n",
01669             rxmin, rymin, rxmax, rymax );
01670     }
01671 }
01672 
01673 //--------------------------------------------------------------------------
01674 // void plsdiplt
01675 //
01676 // Set window into plot space
01677 //--------------------------------------------------------------------------
01678 
01679 void
01680 c_plsdiplt( PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax )
01681 {
01682     plsc->dipxmin = ( xmin < xmax ) ? xmin : xmax;
01683     plsc->dipxmax = ( xmin < xmax ) ? xmax : xmin;
01684     plsc->dipymin = ( ymin < ymax ) ? ymin : ymax;
01685     plsc->dipymax = ( ymin < ymax ) ? ymax : ymin;
01686 
01687     if ( xmin == 0. && xmax == 1. && ymin == 0. && ymax == 1. )
01688     {
01689         plsc->difilt &= ~PLDI_PLT;
01690         return;
01691     }
01692 
01693     plsc->difilt |= PLDI_PLT;
01694     pldi_ini();
01695 }
01696 
01697 //--------------------------------------------------------------------------
01698 // void plsdiplz
01699 //
01700 // Set window into plot space incrementally (zoom)
01701 //--------------------------------------------------------------------------
01702 
01703 void
01704 c_plsdiplz( PLFLT xmin, PLFLT ymin, PLFLT xmax, PLFLT ymax )
01705 {
01706     if ( plsc->difilt & PLDI_PLT )
01707     {
01708         xmin = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmin;
01709         ymin = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymin;
01710         xmax = plsc->dipxmin + ( plsc->dipxmax - plsc->dipxmin ) * xmax;
01711         ymax = plsc->dipymin + ( plsc->dipymax - plsc->dipymin ) * ymax;
01712     }
01713 
01714     plsdiplt( xmin, ymin, xmax, ymax );
01715 }
01716 
01717 //--------------------------------------------------------------------------
01718 // void calc_diplt
01719 //
01720 // Calculate transformation coefficients to set window into plot space.
01721 //
01722 // Note: if driver has requested to handle these commands itself, we must
01723 // send the appropriate escape command.  If the driver succeeds it will
01724 // cancel the filter operation.  The command is deferred until this point
01725 // to ensure that the driver has been initialized.
01726 //--------------------------------------------------------------------------
01727 
01728 static void
01729 calc_diplt( void )
01730 {
01731     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
01732 
01733     if ( plsc->dev_di )
01734     {
01735         char *save_locale = plsave_set_locale();
01736         if ( !plsc->stream_closed )
01737         {
01738             ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
01739                 PLESC_DI, NULL );
01740         }
01741         plrestore_locale( save_locale );
01742     }
01743 
01744     if ( !( plsc->difilt & PLDI_PLT ) )
01745         return;
01746 
01747     pxmin = plP_dcpcx( plsc->dipxmin );
01748     pxmax = plP_dcpcx( plsc->dipxmax );
01749     pymin = plP_dcpcy( plsc->dipymin );
01750     pymax = plP_dcpcy( plsc->dipymax );
01751 
01752     pxlen = pxmax - pxmin;
01753     pylen = pymax - pymin;
01754     pxlen = MAX( 1, pxlen );
01755     pylen = MAX( 1, pylen );
01756 
01757     plsc->dipxax = plsc->phyxlen / (double) pxlen;
01758     plsc->dipyay = plsc->phyylen / (double) pylen;
01759     plsc->dipxb  = plsc->phyxmi - plsc->dipxax * pxmin;
01760     plsc->dipyb  = plsc->phyymi - plsc->dipyay * pymin;
01761 }
01762 
01763 //--------------------------------------------------------------------------
01764 // void plgdiplt
01765 //
01766 // Retrieve current window into plot space
01767 //--------------------------------------------------------------------------
01768 
01769 void
01770 c_plgdiplt( PLFLT *p_xmin, PLFLT *p_ymin, PLFLT *p_xmax, PLFLT *p_ymax )
01771 {
01772     *p_xmin = plsc->dipxmin;
01773     *p_xmax = plsc->dipxmax;
01774     *p_ymin = plsc->dipymin;
01775     *p_ymax = plsc->dipymax;
01776 }
01777 
01778 //--------------------------------------------------------------------------
01779 // void plsdidev
01780 //
01781 // Set window into device space using margin, aspect ratio, and
01782 // justification.  If you want to just use the previous value for any of
01783 // these, just pass in the magic value PL_NOTSET.
01784 //
01785 // It is unlikely that one should ever need to change the aspect ratio
01786 // but it's in there for completeness.
01787 //--------------------------------------------------------------------------
01788 
01789 void
01790 c_plsdidev( PLFLT mar, PLFLT aspect, PLFLT jx, PLFLT jy )
01791 {
01792     plsetvar( plsc->mar, mar );
01793     plsetvar( plsc->aspect, aspect );
01794     plsetvar( plsc->jx, jx );
01795     plsetvar( plsc->jy, jy );
01796 
01797     if ( mar == 0. && aspect == 0. && jx == 0. && jy == 0. &&
01798          !( plsc->difilt & PLDI_ORI ) )
01799     {
01800         plsc->difilt &= ~PLDI_DEV;
01801         return;
01802     }
01803 
01804     plsc->difilt |= PLDI_DEV;
01805     pldi_ini();
01806 }
01807 
01808 //--------------------------------------------------------------------------
01809 // void calc_didev
01810 //
01811 // Calculate transformation coefficients to set window into device space.
01812 // Calculates relative window bounds and calls plsdidxy to finish the job.
01813 //--------------------------------------------------------------------------
01814 
01815 static void
01816 calc_didev( void )
01817 {
01818     PLFLT lx, ly, aspect, aspdev;
01819     PLFLT xmin, xmax, xlen, ymin, ymax, ylen;
01820     PLINT pxmin, pxmax, pymin, pymax, pxlen, pylen;
01821 
01822     if ( plsc->dev_di )
01823     {
01824         char *save_locale = plsave_set_locale();
01825         if ( !plsc->stream_closed )
01826         {
01827             ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
01828                 PLESC_DI, NULL );
01829         }
01830         plrestore_locale( save_locale );
01831     }
01832 
01833     if ( !( plsc->difilt & PLDI_DEV ) )
01834         return;
01835 
01836 // Calculate aspect ratio of physical device
01837 
01838     lx     = plsc->phyxlen / plsc->xpmm;
01839     ly     = plsc->phyylen / plsc->ypmm;
01840     aspdev = lx / ly;
01841 
01842     if ( plsc->difilt & PLDI_ORI )
01843         aspect = plsc->aspori;
01844     else
01845         aspect = plsc->aspect;
01846 
01847     if ( aspect <= 0. )
01848         aspect = plsc->aspdev;
01849 
01850 // Failsafe
01851 
01852     plsc->mar = ( plsc->mar > 0.5 ) ? 0.5 : plsc->mar;
01853     plsc->mar = ( plsc->mar < 0.0 ) ? 0.0 : plsc->mar;
01854     plsc->jx  = ( plsc->jx > 0.5 ) ?  0.5 : plsc->jx;
01855     plsc->jx  = ( plsc->jx < -0.5 ) ? -0.5 : plsc->jx;
01856     plsc->jy  = ( plsc->jy > 0.5 ) ?  0.5 : plsc->jy;
01857     plsc->jy  = ( plsc->jy < -0.5 ) ? -0.5 : plsc->jy;
01858 
01859 // Relative device coordinates that neutralize aspect ratio difference
01860 
01861     xlen = ( aspect < aspdev ) ? ( aspect / aspdev ) : 1.0;
01862     ylen = ( aspect < aspdev ) ? 1.0 : ( aspdev / aspect );
01863 
01864     xlen *= ( 1.0 - 2. * plsc->mar );
01865     ylen *= ( 1.0 - 2. * plsc->mar );
01866 
01867     xmin = ( 1. - xlen ) * ( 0.5 + plsc->jx );
01868     xmax = xmin + xlen;
01869 
01870     ymin = ( 1. - ylen ) * ( 0.5 + plsc->jy );
01871     ymax = ymin + ylen;
01872 
01873 // Calculate transformation coefficients
01874 
01875     pxmin = plP_dcpcx( xmin );
01876     pxmax = plP_dcpcx( xmax );
01877     pymin = plP_dcpcy( ymin );
01878     pymax = plP_dcpcy( ymax );
01879 
01880     pxlen = pxmax - pxmin;
01881     pylen = pymax - pymin;
01882     pxlen = MAX( 1, pxlen );
01883     pylen = MAX( 1, pylen );
01884 
01885     plsc->didxax = pxlen / (double) plsc->phyxlen;
01886     plsc->didyay = pylen / (double) plsc->phyylen;
01887     plsc->didxb  = pxmin - plsc->didxax * plsc->phyxmi;
01888     plsc->didyb  = pymin - plsc->didyay * plsc->phyymi;
01889 
01890 // Set clip limits to conform to new page size
01891 
01892     plsc->diclpxmi = (PLINT) ( plsc->didxax * plsc->phyxmi + plsc->didxb );
01893     plsc->diclpxma = (PLINT) ( plsc->didxax * plsc->phyxma + plsc->didxb );
01894     plsc->diclpymi = (PLINT) ( plsc->didyay * plsc->phyymi + plsc->didyb );
01895     plsc->diclpyma = (PLINT) ( plsc->didyay * plsc->phyyma + plsc->didyb );
01896 }
01897 
01898 //--------------------------------------------------------------------------
01899 // void plgdidev
01900 //
01901 // Retrieve current window into device space
01902 //--------------------------------------------------------------------------
01903 
01904 void
01905 c_plgdidev( PLFLT *p_mar, PLFLT *p_aspect, PLFLT *p_jx, PLFLT *p_jy )
01906 {
01907     *p_mar    = plsc->mar;
01908     *p_aspect = plsc->aspect;
01909     *p_jx     = plsc->jx;
01910     *p_jy     = plsc->jy;
01911 }
01912 
01913 //--------------------------------------------------------------------------
01914 // void plsdiori
01915 //
01916 // Set plot orientation, specifying rotation in units of pi/2.
01917 //--------------------------------------------------------------------------
01918 
01919 void
01920 c_plsdiori( PLFLT rot )
01921 {
01922     plsc->diorot = rot;
01923     if ( rot == 0. )
01924     {
01925         plsc->difilt &= ~PLDI_ORI;
01926         pldi_ini();
01927         return;
01928     }
01929 
01930     plsc->difilt |= PLDI_ORI;
01931     pldi_ini();
01932 }
01933 
01934 //--------------------------------------------------------------------------
01935 // void calc_diori
01936 //
01937 // Calculate transformation coefficients to arbitrarily orient plot.
01938 // Preserve aspect ratios so the output doesn't suck.
01939 //--------------------------------------------------------------------------
01940 
01941 static void
01942 calc_diori( void )
01943 {
01944     PLFLT cost, sint;
01945     PLFLT x0, y0, lx, ly, aspect;
01946     PLFLT affine_result[NAFFINE], affine_left[NAFFINE];
01947 
01948     if ( plsc->dev_di )
01949     {
01950         char *save_locale = plsave_set_locale();
01951         if ( !plsc->stream_closed )
01952         {
01953             ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
01954                 PLESC_DI, NULL );
01955         }
01956         plrestore_locale( save_locale );
01957     }
01958 
01959     if ( !( plsc->difilt & PLDI_ORI ) )
01960         return;
01961 
01962 // Center point of rotation
01963 
01964     x0 = ( plsc->phyxma + plsc->phyxmi ) / 2.;
01965     y0 = ( plsc->phyyma + plsc->phyymi ) / 2.;
01966 
01967 // Rotation
01968 
01969     cost = ABS( cos( plsc->diorot * PI / 2. ) );
01970     sint = ABS( sin( plsc->diorot * PI / 2. ) );
01971 
01972 // Flip aspect ratio as necessary.  Grungy but I don't see a better way
01973 
01974     aspect = plsc->aspect;
01975     if ( aspect == 0. )
01976         aspect = plsc->aspdev;
01977 
01978     if ( plsc->freeaspect )
01979         plsc->aspori = aspect;
01980     else
01981         plsc->aspori = ( aspect * cost + sint ) / ( aspect * sint + cost );
01982 
01983     if ( !( plsc->difilt & PLDI_DEV ) )
01984     {
01985         plsc->difilt |= PLDI_DEV;
01986         setdef_didev();
01987     }
01988     calc_didev();
01989 
01990     // Compute scale factors for relative device coordinates.  Only
01991     // the aspect ratio of lx to ly matters.  Note, plsc->phyxlen and
01992     // plsc->phyylen are in PLplot core library coordinates and don't
01993     // know anything about device coordinates which are likely to have
01994     // a quite different aspect ratio.  So to correct between the two
01995     // coordinate systems must divide plsc->phyxlen/plsc->phyylen by
01996     // plsc->aspori.
01997 
01998     // N.B. comment out this correction because causes other issues.
01999 
02000     //lx = plsc->phyxlen/plsc->aspori;
02001     lx = plsc->phyxlen;
02002     ly = plsc->phyylen;
02003 
02004 // Transformation coefficients
02005 
02006     //
02007     // plsc->dioxax = r11;
02008     // plsc->dioxay = r21 * ( lx / ly );
02009     // plsc->dioxb  = ( 1. - r11 ) * x0 - r21 * y0 * ( lx / ly );
02010     //
02011     // plsc->dioyax = r12 * ( ly / lx );
02012     // plsc->dioyay = r22;
02013     // plsc->dioyb  = ( 1. - r22 ) * y0 - r12 * x0 * ( ly / lx );
02014     //
02015 
02016     // Calculate affine transformation as product of translate to middle
02017     // of device, scale to relative device coordinates, rotate, unscale
02018     // to physical coordinates, untranslate to original zero point.
02019     plP_affine_translate( affine_result, x0, y0 );
02020     plP_affine_scale( affine_left, lx, ly );
02021     plP_affine_multiply( affine_result, affine_left, affine_result );
02022     plP_affine_rotate( affine_left, plsc->diorot * 90. );
02023     plP_affine_multiply( affine_result, affine_left, affine_result );
02024     plP_affine_scale( affine_left, 1. / lx, 1. / ly );
02025     plP_affine_multiply( affine_result, affine_left, affine_result );
02026     plP_affine_translate( affine_left, -x0, -y0 );
02027     plP_affine_multiply( affine_result, affine_left, affine_result );
02028     plsc->dioxax = affine_result[0];
02029     plsc->dioxay = affine_result[2];
02030     plsc->dioxb  = affine_result[4];
02031     plsc->dioyax = affine_result[1];
02032     plsc->dioyay = affine_result[3];
02033     plsc->dioyb  = affine_result[5];
02034 }
02035 
02036 //--------------------------------------------------------------------------
02037 // void plgdiori
02038 //
02039 // Get plot orientation
02040 //--------------------------------------------------------------------------
02041 
02042 void
02043 c_plgdiori( PLFLT *p_rot )
02044 {
02045     *p_rot = plsc->diorot;
02046 }
02047 
02048 //--------------------------------------------------------------------------
02049 // void plsdimap
02050 //
02051 // Set up transformation from metafile coordinates.  The size of the plot is
02052 // scaled so as to preserve aspect ratio.  This isn't intended to be a
02053 // general-purpose facility just yet (not sure why the user would need it,
02054 // for one).
02055 //--------------------------------------------------------------------------
02056 
02057 void
02058 c_plsdimap( PLINT dimxmin, PLINT dimxmax, PLINT dimymin, PLINT dimymax,
02059             PLFLT dimxpmm, PLFLT dimypmm )
02060 {
02061     plsetvar( plsc->dimxmin, dimxmin );
02062     plsetvar( plsc->dimxmax, dimxmax );
02063     plsetvar( plsc->dimymin, dimymin );
02064     plsetvar( plsc->dimymax, dimymax );
02065     plsetvar( plsc->dimxpmm, dimxpmm );
02066     plsetvar( plsc->dimypmm, dimypmm );
02067 
02068     plsc->difilt |= PLDI_MAP;
02069     pldi_ini();
02070 }
02071 
02072 //--------------------------------------------------------------------------
02073 // void calc_dimap
02074 //
02075 // Set up transformation from metafile coordinates.  The size of the plot is
02076 // scaled so as to preserve aspect ratio.  This isn't intended to be a
02077 // general-purpose facility just yet (not sure why the user would need it,
02078 // for one).
02079 //--------------------------------------------------------------------------
02080 
02081 static void
02082 calc_dimap()
02083 {
02084     PLFLT lx, ly;
02085     PLINT pxmin, pxmax, pymin, pymax;
02086     PLFLT dimxlen, dimylen, pxlen, pylen;
02087 
02088     if ( ( plsc->dimxmin == plsc->phyxmi ) && ( plsc->dimxmax == plsc->phyxma ) &&
02089          ( plsc->dimymin == plsc->phyymi ) && ( plsc->dimymax == plsc->phyyma ) &&
02090          ( plsc->dimxpmm == plsc->xpmm ) && ( plsc->dimypmm == plsc->ypmm ) )
02091     {
02092         plsc->difilt &= ~PLDI_MAP;
02093         return;
02094     }
02095 
02096 // Set default aspect ratio
02097 
02098     lx = ( plsc->dimxmax - plsc->dimxmin + 1 ) / plsc->dimxpmm;
02099     ly = ( plsc->dimymax - plsc->dimymin + 1 ) / plsc->dimypmm;
02100 
02101     plsc->aspdev = lx / ly;
02102 
02103 // Build transformation to correct physical coordinates
02104 
02105     dimxlen = plsc->dimxmax - plsc->dimxmin;
02106     dimylen = plsc->dimymax - plsc->dimymin;
02107 
02108     pxmin = plsc->phyxmi;
02109     pxmax = plsc->phyxma;
02110     pymin = plsc->phyymi;
02111     pymax = plsc->phyyma;
02112     pxlen = pxmax - pxmin;
02113     pylen = pymax - pymin;
02114 
02115     plsc->dimxax = pxlen / dimxlen;
02116     plsc->dimyay = pylen / dimylen;
02117     plsc->dimxb  = pxmin - pxlen * plsc->dimxmin / dimxlen;
02118     plsc->dimyb  = pymin - pylen * plsc->dimymin / dimylen;
02119 }
02120 
02121 //--------------------------------------------------------------------------
02122 // void plflush()
02123 //
02124 // Flushes the output stream.  Use sparingly, if at all.
02125 //--------------------------------------------------------------------------
02126 
02127 void
02128 c_plflush( void )
02129 {
02130     if ( plsc->dev_flush )
02131     {
02132         char *save_locale = plsave_set_locale();
02133         if ( !plsc->stream_closed )
02134         {
02135             ( *plsc->dispatch_table->pl_esc )( (struct PLStream_struct *) plsc,
02136                 PLESC_FLUSH, NULL );
02137         }
02138         plrestore_locale( save_locale );
02139     }
02140     else
02141     {
02142         if ( plsc->OutFile != NULL )
02143             fflush( plsc->OutFile );
02144     }
02145 }
02146 
02147 //--------------------------------------------------------------------------
02148 // Startup routines.
02149 //--------------------------------------------------------------------------
02150 
02151 //--------------------------------------------------------------------------
02152 // void pllib_init()
02153 //
02154 // Initialize library.  Called internally by every startup routine.
02155 // Everything you want to always be initialized before plinit() is called
02156 // you should put here.  E.g. dispatch table setup, rcfile read, etc.
02157 //--------------------------------------------------------------------------
02158 
02159 void
02160 pllib_init()
02161 {
02162     if ( lib_initialized )
02163         return;
02164     lib_initialized = 1;
02165 
02166 #ifdef ENABLE_DYNDRIVERS
02167 // Create libltdl resources
02168     lt_dlinit();
02169 #endif
02170 
02171 // Initialize the dispatch table with the info from the static drivers table
02172 // and the available dynamic drivers.
02173 
02174     plInitDispatchTable();
02175 }
02176 
02177 //--------------------------------------------------------------------------
02178 // void plstar(nx, ny)
02179 //
02180 // Initialize PLplot, passing in the windows/page settings.
02181 //--------------------------------------------------------------------------
02182 
02183 void
02184 c_plstar( PLINT nx, PLINT ny )
02185 {
02186     pllib_init();
02187 
02188     if ( plsc->level != 0 )
02189         plend1();
02190 
02191     plssub( nx, ny );
02192 
02193     c_plinit();
02194 }
02195 
02196 //--------------------------------------------------------------------------
02197 // void plstart(devname, nx, ny)
02198 //
02199 // Initialize PLplot, passing the device name and windows/page settings.
02200 //--------------------------------------------------------------------------
02201 
02202 void
02203 c_plstart( const char *devname, PLINT nx, PLINT ny )
02204 {
02205     pllib_init();
02206 
02207     if ( plsc->level != 0 )
02208         plend1();
02209 
02210     plssub( nx, ny );
02211     plsdev( devname );
02212 
02213     c_plinit();
02214 }
02215 
02216 //--------------------------------------------------------------------------
02217 // void plinit()
02218 //
02219 // Initializes PLplot, using preset or default options.
02220 //--------------------------------------------------------------------------
02221 
02222 void
02223 c_plinit( void )
02224 {
02225     PLFLT lx, ly, xpmm_loc, ypmm_loc, aspect_old, aspect_new;
02226     PLINT inc = 0, del = 2000;
02227 
02228     pllib_init();
02229 
02230     if ( plsc->level != 0 )
02231         plend1();
02232 
02233 // Set stream number
02234 
02235     plsc->ipls = ipls;
02236 
02237 // Set up devices
02238 
02239     pllib_devinit();
02240 
02241 // Auxiliary stream setup
02242 
02243     plstrm_init();
02244 
02245 // Set title for window to a sensible default if not defined
02246     if ( plsc->plwindow == NULL )
02247     {
02248         if ( plsc->program )
02249         {
02250             if ( ( plsc->plwindow = (char *) malloc( (size_t) ( 1 + strlen( plsc->program ) ) * sizeof ( char ) ) ) == NULL )
02251             {
02252                 plexit( "plinit: Insufficient memory" );
02253             }
02254             strcpy( plsc->plwindow, plsc->program );
02255         }
02256         else
02257         {
02258             if ( ( plsc->plwindow = (char *) malloc( (size_t) 7 * sizeof ( char ) ) ) == NULL )
02259             {
02260                 plexit( "plinit: Insufficient memory" );
02261             }
02262             strcpy( plsc->plwindow, "PLplot" );
02263         }
02264     }
02265 
02266 // Initialize device & first page
02267 
02268     plP_init();
02269     plP_bop();
02270     plsc->level = 1;
02271 
02272 
02273 // The driver options are freed after driver initialisation,
02274 // since it is assumed that in this function options are
02275 // processed and stored somewhere else. For further driver
02276 // initialisations (e.g. copy stream) there are no driver
02277 // options defined.
02278 
02279     plP_FreeDrvOpts();
02280 
02281 // Calculate factor such that the character aspect ratio is preserved
02282 // when the overall aspect ratio is changed, i.e., if portrait mode is
02283 // requested (only honored for subset of drivers) or if the aspect ratio
02284 // is specified in any way, or if a 90 deg rotation occurs with
02285 // -freeaspect.
02286 
02287 // Case where plsc->aspect has a value.... (e.g., -a aspect on the
02288 // command line or 2nd parameter of plsdidev specified)
02289     if ( plsc->aspect > 0. )
02290     {
02291         lx               = plsc->phyxlen / plsc->xpmm;
02292         ly               = plsc->phyylen / plsc->ypmm;
02293         aspect_old       = lx / ly;
02294         aspect_new       = plsc->aspect;
02295         plsc->caspfactor = sqrt( aspect_old / aspect_new );
02296     }
02297 // Case of 90 deg rotations with -freeaspect (this is also how portrait
02298 // mode is implemented for the drivers that honor -portrait).
02299     else if ( plsc->freeaspect && ABS( cos( plsc->diorot * PI / 2. ) ) <= 1.e-5 )
02300     {
02301         lx               = plsc->phyxlen / plsc->xpmm;
02302         ly               = plsc->phyylen / plsc->ypmm;
02303         aspect_old       = lx / ly;
02304         aspect_new       = ly / lx;
02305         plsc->caspfactor = sqrt( aspect_old / aspect_new );
02306     }
02307 
02308     else
02309         plsc->caspfactor = 1.;
02310 
02311 // Load fonts
02312 
02313     plsc->cfont = 1;
02314     plfntld( initfont );
02315 
02316 // Set up subpages
02317 
02318     plP_subpInit();
02319 
02320 // Set up number of allowed digits before switching to scientific notation
02321 // The user can always change this
02322 
02323     if ( plsc->xdigmax == 0 )
02324         plsc->xdigmax = 4;
02325 
02326     if ( plsc->ydigmax == 0 )
02327         plsc->ydigmax = 4;
02328 
02329     if ( plsc->zdigmax == 0 )
02330         plsc->zdigmax = 3;
02331 
02332     if ( plsc->timefmt == NULL )
02333         c_pltimefmt( "%c" );
02334 
02335     // Use default transformation between continuous and broken-down time
02336     // (and vice versa) if the transformation has not yet been defined
02337     // for this stream.
02338     if ( plsc->qsasconfig == NULL )
02339         c_plconfigtime( 0., 0., 0., 0x0, 0, 0, 0, 0, 0, 0, 0. );
02340 
02341 // Switch to graphics mode and set color and arrow style
02342 
02343     plgra();
02344     plcol0( 1 );
02345 
02346     pllsty( 1 );
02347     plpat( 1, &inc, &del );
02348 
02349     // Set up default arrow style;
02350     plsvect( NULL, NULL, 6, 0 );
02351 
02352 // Set clip limits.
02353 
02354     plsc->clpxmi = plsc->phyxmi;
02355     plsc->clpxma = plsc->phyxma;
02356     plsc->clpymi = plsc->phyymi;
02357     plsc->clpyma = plsc->phyyma;
02358 
02359 // Page aspect ratio.
02360 
02361     lx           = plsc->phyxlen / plsc->xpmm;
02362     ly           = plsc->phyylen / plsc->ypmm;
02363     plsc->aspdev = lx / ly;
02364 
02365 // Initialize driver interface
02366 
02367     pldi_ini();
02368 
02369 // Apply compensating factor to original xpmm and ypmm so that
02370 // character aspect ratio is preserved when overall aspect ratio
02371 // is changed.  This must appear here in the code because previous
02372 // code in this routine and in routines that it calls must use the original
02373 // values of xpmm and ypmm before the compensating factor is applied.
02374 
02375     plP_gpixmm( &xpmm_loc, &ypmm_loc );
02376     plP_setpxl( xpmm_loc * plsc->caspfactor, ypmm_loc / plsc->caspfactor );
02377 }
02378 
02379 //--------------------------------------------------------------------------
02380 // void plend()
02381 //
02382 // End a plotting session for all open streams.
02383 //--------------------------------------------------------------------------
02384 
02385 void
02386 c_plend( void )
02387 {
02388     PLINT i;
02389 
02390     if ( lib_initialized == 0 )
02391         return;
02392 
02393     for ( i = PL_NSTREAMS - 1; i >= 0; i-- )
02394     {
02395         if ( pls[i] != NULL )
02396         {
02397             plsstrm( i );
02398             c_plend1();
02399         }
02400     }
02401     plfontrel();
02402 #ifdef ENABLE_DYNDRIVERS
02403 // Release the libltdl resources
02404     lt_dlexit();
02405 // Free up memory allocated to the dispatch tables
02406     for ( i = 0; i < npldynamicdevices; i++ )
02407     {
02408         free_mem( loadable_device_list[i].devnam );
02409         free_mem( loadable_device_list[i].description );
02410         free_mem( loadable_device_list[i].drvnam );
02411         free_mem( loadable_device_list[i].tag );
02412     }
02413     free_mem( loadable_device_list );
02414     for ( i = 0; i < nloadabledrivers; i++ )
02415     {
02416         free_mem( loadable_driver_list[i].drvnam );
02417     }
02418     free_mem( loadable_driver_list );
02419     for ( i = nplstaticdevices; i < npldrivers; i++ )
02420     {
02421         free_mem( dispatch_table[i]->pl_MenuStr );
02422         free_mem( dispatch_table[i]->pl_DevName );
02423         free_mem( dispatch_table[i] );
02424     }
02425 #endif
02426     for ( i = 0; i < nplstaticdevices; i++ )
02427     {
02428         free_mem( dispatch_table[i] );
02429     }
02430     free_mem( dispatch_table );
02431 
02432     lib_initialized = 0;
02433 }
02434 
02435 //--------------------------------------------------------------------------
02436 // void plend1()
02437 //
02438 // End a plotting session for the current stream only.  After the stream is
02439 // ended the memory associated with the stream's PLStream data structure is
02440 // freed (for stream > 0), and the stream counter is set to 0 (the default).
02441 //--------------------------------------------------------------------------
02442 
02443 void
02444 c_plend1( void )
02445 {
02446     if ( plsc->level > 0 )
02447     {
02448         plP_eop();
02449         plP_tidy();
02450         plsc->level = 0;
02451     }
02452     // Move from plP_tidy because FileName may be set even if level == 0
02453     if ( plsc->FileName )
02454         free_mem( plsc->FileName );
02455 
02456 // Free all malloc'ed stream memory
02457 
02458     free_mem( plsc->cmap0 );
02459     free_mem( plsc->cmap1 );
02460     free_mem( plsc->plwindow );
02461     free_mem( plsc->geometry );
02462     free_mem( plsc->dev );
02463     free_mem( plsc->BaseName );
02464 #ifndef BUFFERED_FILE
02465     free_mem( plsc->plbuf_buffer );
02466 #endif
02467     if ( plsc->program )
02468         free_mem( plsc->program );
02469     if ( plsc->server_name )
02470         free_mem( plsc->server_name );
02471     if ( plsc->server_host )
02472         free_mem( plsc->server_host );
02473     if ( plsc->server_port )
02474         free_mem( plsc->server_port );
02475     if ( plsc->user )
02476         free_mem( plsc->user );
02477     if ( plsc->plserver )
02478         free_mem( plsc->plserver );
02479     if ( plsc->auto_path )
02480         free_mem( plsc->auto_path );
02481 
02482     if ( plsc->arrow_x )
02483         free_mem( plsc->arrow_x );
02484     if ( plsc->arrow_y )
02485         free_mem( plsc->arrow_y );
02486 
02487     if ( plsc->timefmt )
02488         free_mem( plsc->timefmt );
02489 
02490     // Close qsastime library for this stream that was opened by
02491     // plconfigtime call in plinit.
02492 
02493     closeqsas( &( plsc->qsasconfig ) );
02494 
02495 // Free malloc'ed stream if not in initial stream, else clear it out
02496 
02497     if ( ipls > 0 )
02498     {
02499         free_mem( plsc );
02500         pls[ipls] = NULL;
02501         plsstrm( 0 );
02502     }
02503     else
02504     {
02505         memset( (char *) pls[ipls], 0, sizeof ( PLStream ) );
02506     }
02507 }
02508 
02509 //--------------------------------------------------------------------------
02510 // void plsstrm
02511 //
02512 // Set stream number.  If the data structure for a new stream is
02513 // unallocated, we allocate it here.
02514 //--------------------------------------------------------------------------
02515 
02516 void
02517 c_plsstrm( PLINT strm )
02518 {
02519     if ( strm < 0 || strm >= PL_NSTREAMS )
02520     {
02521         fprintf( stderr,
02522             "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
02523             (int) strm, PL_NSTREAMS );
02524     }
02525     else
02526     {
02527         ipls = strm;
02528         if ( pls[ipls] == NULL )
02529         {
02530             pls[ipls] = (PLStream *) malloc( (size_t) sizeof ( PLStream ) );
02531             if ( pls[ipls] == NULL )
02532                 plexit( "plsstrm: Out of memory." );
02533 
02534             memset( (char *) pls[ipls], 0, sizeof ( PLStream ) );
02535         }
02536         plsc       = pls[ipls];
02537         plsc->ipls = ipls;
02538     }
02539 }
02540 
02541 //--------------------------------------------------------------------------
02542 // void plgstrm
02543 //
02544 // Get current stream number.
02545 //--------------------------------------------------------------------------
02546 
02547 void
02548 c_plgstrm( PLINT *p_strm )
02549 {
02550     *p_strm = ipls;
02551 }
02552 
02553 //--------------------------------------------------------------------------
02554 // void plmkstrm
02555 //
02556 // Creates a new stream and makes it the default.  Differs from using
02557 // plsstrm(), in that a free stream number is found, and returned.
02558 //
02559 // Unfortunately, I /have/ to start at stream 1 and work upward, since
02560 // stream 0 is preallocated.  One of the BIG flaws in the PLplot API is
02561 // that no initial, library-opening call is required.  So stream 0 must be
02562 // preallocated, and there is no simple way of determining whether it is
02563 // already in use or not.
02564 //--------------------------------------------------------------------------
02565 
02566 void
02567 c_plmkstrm( PLINT *p_strm )
02568 {
02569     int i;
02570 
02571     for ( i = 1; i < PL_NSTREAMS; i++ )
02572     {
02573         if ( pls[i] == NULL )
02574             break;
02575     }
02576 
02577     if ( i == PL_NSTREAMS )
02578     {
02579         fprintf( stderr, "plmkstrm: Cannot create new stream\n" );
02580         *p_strm = -1;
02581     }
02582     else
02583     {
02584         *p_strm = i;
02585         plsstrm( i );
02586     }
02587     plstrm_init();
02588 }
02589 
02590 //--------------------------------------------------------------------------
02591 // void plstrm_init
02592 //
02593 // Does required startup initialization of a stream.  Should be called right
02594 // after creating one (for allocating extra memory, etc).  Users shouldn't
02595 // need to call this directly.
02596 //
02597 // This function can be called multiple times for a given stream, in which
02598 // case only the first call produces any effect.  For streams >= 1, which
02599 // are created dynamically, this is called by the routine that allocates
02600 // the stream.  Stream 0, which is preallocated, is much harder to deal with
02601 // because any of a number of different calls may be the first call to the
02602 // library.  This is handled by just calling plstrm_init() from every
02603 // function that might be called first.  Sucks, but it should work.
02604 //--------------------------------------------------------------------------
02605 
02606 void
02607 plstrm_init( void )
02608 {
02609     if ( !plsc->initialized )
02610     {
02611         plsc->initialized = 1;
02612 
02613         if ( plsc->cmap0 == NULL )
02614             plspal0( "" );
02615 
02616         if ( plsc->cmap1 == NULL )
02617             plspal1( "", TRUE );
02618 
02619         // Set continuous plots to use the full color map 1 range
02620         plsc->cmap1_min = 0.0;
02621         plsc->cmap1_max = 1.0;
02622     }
02623 
02624     plsc->psdoc = NULL;
02625 }
02626 
02627 //--------------------------------------------------------------------------
02628 // pl_cpcolor
02629 //
02630 // Utility to copy one PLColor to another.
02631 //--------------------------------------------------------------------------
02632 
02633 void
02634 pl_cpcolor( PLColor *to, PLColor *from )
02635 {
02636     to->r = from->r;
02637     to->g = from->g;
02638     to->b = from->b;
02639     to->a = from->a;
02640 }
02641 
02642 //--------------------------------------------------------------------------
02643 // void plcpstrm
02644 //
02645 // Copies state parameters from the reference stream to the current stream.
02646 // Tell driver interface to map device coordinates unless flags == 1.
02647 //
02648 // This function is used for making save files of selected plots (e.g.
02649 // from the TK driver).  After initializing, you can get a copy of the
02650 // current plot to the specified device by switching to this stream and
02651 // issuing a plcpstrm() and a plreplot(), with calls to plbop() and
02652 // pleop() as appropriate.  The plot buffer must have previously been
02653 // enabled (done automatically by some display drivers, such as X).
02654 //--------------------------------------------------------------------------
02655 
02656 void
02657 c_plcpstrm( PLINT iplsr, PLINT flags )
02658 {
02659     int      i;
02660     PLStream *plsr;
02661 
02662     plsr = pls[iplsr];
02663     if ( plsr == NULL )
02664     {
02665         fprintf( stderr, "plcpstrm: stream %d not in use\n", (int) iplsr );
02666         return;
02667     }
02668 
02669 // May be debugging
02670 
02671     plsc->debug = plsr->debug;
02672 
02673 // Plot buffer -- need to copy file pointer so that plreplot() works
02674 // This also prevents inadvertent writes into the plot buffer
02675 
02676 #ifdef BUFFERED_FILE
02677     plsc->plbufFile = plsr->plbufFile;
02678 #else
02679     plsc->plbuf_buffer_grow = plsr->plbuf_buffer_grow;
02680     plsc->plbuf_buffer_size = plsr->plbuf_buffer_size;
02681     plsc->plbuf_top         = plsr->plbuf_top;
02682     plsc->plbuf_readpos     = plsr->plbuf_readpos;
02683     if ( ( plsc->plbuf_buffer = malloc( plsc->plbuf_buffer_size ) ) == NULL )
02684         plexit( "plcpstrm: Error allocating plot buffer." );
02685     memcpy( plsc->plbuf_buffer, plsr->plbuf_buffer, plsr->plbuf_top );
02686 #endif
02687 
02688 // Driver interface
02689 // Transformation must be recalculated in current driver coordinates
02690 
02691     if ( plsr->difilt & PLDI_PLT )
02692         plsdiplt( plsr->dipxmin, plsr->dipymin, plsr->dipxmax, plsr->dipymax );
02693 
02694     if ( plsr->difilt & PLDI_DEV )
02695         plsdidev( plsr->mar, plsr->aspect, plsr->jx, plsr->jy );
02696 
02697     if ( plsr->difilt & PLDI_ORI )
02698         plsdiori( plsr->diorot );
02699 
02700 // Map device coordinates
02701 
02702     if ( !( flags & 0x01 ) )
02703     {
02704         pldebug( "plcpstrm", "mapping parameters: %d %d %d %d %f %f\n",
02705             plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
02706             plsr->xpmm, plsr->ypmm );
02707         plsdimap( plsr->phyxmi, plsr->phyxma, plsr->phyymi, plsr->phyyma,
02708             plsr->xpmm, plsr->ypmm );
02709     }
02710 
02711 // current color
02712 
02713     pl_cpcolor( &plsc->curcolor, &plsr->curcolor );
02714 
02715 // cmap 0
02716 
02717     plsc->icol0 = plsr->icol0;
02718     plsc->ncol0 = plsr->ncol0;
02719     if ( plsc->cmap0 != NULL )
02720         free( (void *) plsc->cmap0 );
02721 
02722     if ( ( plsc->cmap0 = (PLColor *) calloc( 1, (size_t) plsc->ncol0 * sizeof ( PLColor ) ) ) == NULL )
02723     {
02724         plexit( "c_plcpstrm: Insufficient memory" );
02725     }
02726 
02727     for ( i = 0; i < plsc->ncol0; i++ )
02728         pl_cpcolor( &plsc->cmap0[i], &plsr->cmap0[i] );
02729 
02730 // cmap 1
02731 
02732     plsc->icol1     = plsr->icol1;
02733     plsc->ncol1     = plsr->ncol1;
02734     plsc->cmap1_min = plsr->cmap1_min;
02735     plsc->cmap1_max = plsr->cmap1_max;
02736     if ( plsc->cmap1 != NULL )
02737         free( (void *) plsc->cmap1 );
02738 
02739     if ( ( plsc->cmap1 = (PLColor *) calloc( 1, (size_t) plsc->ncol1 * sizeof ( PLColor ) ) ) == NULL )
02740     {
02741         plexit( "c_plcpstrm: Insufficient memory" );
02742     }
02743 
02744     for ( i = 0; i < plsc->ncol1; i++ )
02745         pl_cpcolor( &plsc->cmap1[i], &plsr->cmap1[i] );
02746 
02747 // Initialize if it hasn't been done yet.
02748 
02749     if ( plsc->level == 0 )
02750         plinit();
02751 }
02752 
02753 //--------------------------------------------------------------------------
02754 // pllib_devinit()
02755 //
02756 // Does preliminary setup of device driver.
02757 //
02758 // This function (previously plGetDev) used to be what is now shown as
02759 // plSelectDev below.  However, the situation is a bit more complicated now in
02760 // the dynloadable drivers era.  We now have to:
02761 //
02762 // 1) Make sure the dispatch table is initialized to the union of static
02763 //    drivers and available dynamic drivers (done from pllib_init now).
02764 // 2) Allow the user to select the desired device.
02765 // 3) Initialize the dispatch table entries for the selected device, in the
02766 //    case that it is a dynloadable driver that has not yet been loaded.
02767 //
02768 // Also made non-static, in order to allow some device calls to be made prior
02769 // to calling plinit().  E.g. plframe needs to tell the X driver to create its
02770 // internal data structure during widget construction time (using the escape
02771 // function), but doesn't call plinit() until the plframe is actually mapped.
02772 //--------------------------------------------------------------------------
02773 
02774 void
02775 pllib_devinit()
02776 {
02777     if ( plsc->dev_initialized )
02778         return;
02779     plsc->dev_initialized = 1;
02780 
02781     plSelectDev();
02782 
02783     plLoadDriver();
02784 
02785 // offset by one since table is zero-based, but input list is not
02786     plsc->dispatch_table = dispatch_table[plsc->device - 1];
02787 }
02788 
02789 int plInBuildTree()
02790 {
02791     static int inited      = 0;
02792     static int inBuildTree = 0;
02793 
02794     if ( inited == 0 )
02795     {
02796         int  len_currdir, len_builddir;
02797         char currdir[PLPLOT_MAX_PATH], *pcurrdir = currdir;
02798         char builddir[PLPLOT_MAX_PATH], *pbuilddir = builddir;
02799 
02800 
02801         if ( getcwd( currdir, PLPLOT_MAX_PATH ) == NULL )
02802         {
02803             pldebug( "plInBuildTree():", "Not enough buffer space" );
02804         }
02805         else
02806         {
02807             // The chdir / getcwd call is to ensure we get the physical
02808             // path without any symlinks
02809             // Ignore error in chdir - build tree may not exist
02810             if ( chdir( BUILD_DIR ) == 0 )
02811             {
02812                 if ( getcwd( builddir, PLPLOT_MAX_PATH ) == NULL )
02813                 {
02814                     pldebug( "plInBuildTree():", "Not enough buffer space" );
02815                 }
02816                 else
02817                 {
02818                     len_currdir  = strlen( currdir );
02819                     len_builddir = strlen( builddir );
02820 #if defined ( _MSC_VER )
02821                     // On Windows all parts of the path are case insensitive
02822                     // so convert to lower case for the comparison.
02823                     for (; *pcurrdir; ++pcurrdir )
02824                         *pcurrdir = tolower( *pcurrdir );
02825                     for (; *pbuilddir; ++pbuilddir )
02826                         *pbuilddir = tolower( *pbuilddir );
02827 #define PLPLOT_PATH_DELIMITER    '\\'
02828 #else
02829 #define PLPLOT_PATH_DELIMITER    '/'
02830 #endif
02831                     // builddir does not have trailing path delimiter
02832                     // so the strncmp comparison checks if currdir is
02833                     // exactly the builddir or builddir with a string
02834                     // appended.  So if that test succeeds, then check
02835                     // further if the currdir is exactly the build_dir
02836                     // or the appended string starts with the path
02837                     // delimiter, i.e., whether currdir is the builddir or
02838                     // a subdirectory of that directory.
02839                     if ( strncmp( builddir, currdir, len_builddir ) == 0 &&
02840                          ( len_currdir == len_builddir || currdir[len_builddir] == PLPLOT_PATH_DELIMITER ) )
02841                     {
02842                         inBuildTree = 1;
02843                     }
02844                 }
02845                 if ( chdir( currdir ) != 0 )
02846                     pldebug( "plInBuildTree():", "Unable to chdir to current directory" );
02847             }
02848         }
02849         inited = 1;
02850     }
02851     return inBuildTree;
02852 }
02853 
02854 #ifdef ENABLE_DYNDRIVERS
02855 
02856 const char*
02857 plGetDrvDir()
02858 {
02859     const char* drvdir;
02860 
02861 // Get drivers directory in PLPLOT_DRV_DIR or DRV_DIR,
02862 //  on this order
02863 //
02864 
02865     if ( plInBuildTree() == 1 )
02866     {
02867         drvdir = BUILD_DIR "/drivers";
02868         pldebug( "plGetDrvDir", "Using %s as the driver directory.\n", drvdir );
02869     }
02870     else
02871     {
02872         pldebug( "plGetDrvDir", "Trying to read env var PLPLOT_DRV_DIR\n" );
02873         drvdir = getenv( "PLPLOT_DRV_DIR" );
02874 
02875         if ( drvdir == NULL )
02876         {
02877             pldebug( "plGetDrvDir",
02878                 "Will use drivers dir: " DRV_DIR "\n" );
02879             drvdir = DRV_DIR;
02880         }
02881     }
02882 
02883     return drvdir;
02884 }
02885 
02886 #endif
02887 
02888 
02889 //--------------------------------------------------------------------------
02890 // void plInitDispatchTable()
02891 //
02892 // ...
02893 //--------------------------------------------------------------------------
02894 
02895 static int plDispatchSequencer( const void *p1, const void *p2 )
02896 {
02897     const PLDispatchTable* t1 = *(const PLDispatchTable * const *) p1;
02898     const PLDispatchTable* t2 = *(const PLDispatchTable * const *) p2;
02899 
02900 //     printf( "sorting: t1.name=%s t1.seq=%d t2.name=%s t2.seq=%d\n",
02901 //             t1->pl_DevName, t1->pl_seq, t2->pl_DevName, t2->pl_seq );
02902 
02903     return t1->pl_seq - t2->pl_seq;
02904 }
02905 
02906 static void
02907 plInitDispatchTable()
02908 {
02909     int n;
02910 
02911 #ifdef ENABLE_DYNDRIVERS
02912     char buf[BUFFER2_SIZE];
02913     const char   * drvdir;
02914     char         *devnam, *devdesc, *devtype, *driver, *tag, *seqstr;
02915     int seq;
02916     int i, j, driver_found, done = 0;
02917     FILE         *fp_drvdb   = NULL;
02918     DIR          * dp_drvdir = NULL;
02919     struct dirent* entry;
02920     // lt_dlhandle dlhand;
02921 
02922     // Make sure driver counts are zeroed
02923     npldynamicdevices = 0;
02924     nloadabledrivers  = 0;
02925 
02926 // Open a temporary file in which all the plD_DEVICE_INFO_<driver> strings
02927 // will be stored
02928     fp_drvdb = pl_create_tempfile( NULL );
02929     if ( fp_drvdb == NULL )
02930     {
02931         plabort( "plInitDispatchTable: Could not open temporary file" );
02932         return;
02933     }
02934 
02935 // Open the drivers directory
02936     drvdir    = plGetDrvDir();
02937     dp_drvdir = opendir( drvdir );
02938     if ( dp_drvdir == NULL )
02939     {
02940         fclose( fp_drvdb );
02941         plabort( "plInitDispatchTable: Could not open drivers directory" );
02942         return;
02943     }
02944 
02945 // Loop over each entry in the drivers directory
02946 
02947     pldebug( "plInitDispatchTable", "Scanning dyndrivers dir\n" );
02948     while ( ( entry = readdir( dp_drvdir ) ) != NULL )
02949     {
02950         char   * name = entry->d_name;
02951         // Suffix .driver_info has a length of 12 letters.
02952         size_t len = strlen( name ) - 12;
02953 
02954         pldebug( "plInitDispatchTable",
02955             "Consider file %s\n", name );
02956 
02957 // Only consider entries that have the ".driver_info" suffix
02958         if ( ( len > 0 ) && ( strcmp( name + len, ".driver_info" ) == 0 ) )
02959         {
02960             char path[PLPLOT_MAX_PATH];
02961             FILE * fd;
02962 
02963 // Open the driver's info file
02964             snprintf( path, PLPLOT_MAX_PATH, "%s/%s", drvdir, name );
02965             fd = fopen( path, "r" );
02966             if ( fd == NULL )
02967             {
02968                 closedir( dp_drvdir );
02969                 fclose( fp_drvdb );
02970                 snprintf( buf, BUFFER2_SIZE,
02971                     "plInitDispatchTable: Could not open driver info file %s\n",
02972                     name );
02973                 plabort( buf );
02974                 return;
02975             }
02976 
02977 // Each line in the <driver>.driver_info file corresponds to a specific device.
02978 // Write it to the drivers db file and take care of leading newline
02979 // character
02980 
02981             pldebug( "plInitDispatchTable",
02982                 "Opened driver info file %s\n", name );
02983             while ( fgets( buf, BUFFER2_SIZE, fd ) != NULL )
02984             {
02985                 fprintf( fp_drvdb, "%s", buf );
02986                 if ( buf [strlen( buf ) - 1] != '\n' )
02987                     fprintf( fp_drvdb, "\n" );
02988                 npldynamicdevices++;
02989             }
02990             fclose( fd );
02991         }
02992     }
02993 
02994 // Make sure that the temporary file containing the drivers database
02995 // is ready to read and close the directory handle
02996     fflush( fp_drvdb );
02997     closedir( dp_drvdir );
02998 
02999 #endif
03000 
03001 // Allocate space for the dispatch table.
03002     if ( ( dispatch_table = (PLDispatchTable **)
03003                             malloc( (size_t) ( nplstaticdevices + npldynamicdevices ) * sizeof ( PLDispatchTable * ) ) ) == NULL )
03004     {
03005 #ifdef ENABLE_DYNDRIVERS
03006         fclose( fp_drvdb );
03007 #endif
03008         plexit( "plInitDispatchTable: Insufficient memory" );
03009     }
03010 
03011 // Initialize the dispatch table entries for the static devices by calling
03012 // the dispatch table initialization function for each static device.  This
03013 // is the same function that would be called at load time for dynamic
03014 // drivers.
03015 
03016     for ( n = 0; n < nplstaticdevices; n++ )
03017     {
03018         if ( ( dispatch_table[n] = (PLDispatchTable *) malloc( sizeof ( PLDispatchTable ) ) ) == NULL )
03019         {
03020 #ifdef ENABLE_DYNDRIVERS
03021             fclose( fp_drvdb );
03022 #endif
03023             plexit( "plInitDispatchTable: Insufficient memory" );
03024         }
03025 
03026         ( *static_device_initializers[n] )( dispatch_table[n] );
03027     }
03028     npldrivers = nplstaticdevices;
03029 
03030 #ifdef ENABLE_DYNDRIVERS
03031 
03032 // Allocate space for the device and driver specs.  We may not use all of
03033 // these driver descriptors, but we obviously won't need more drivers than
03034 // devices...
03035     if ( ( ( loadable_device_list = malloc( (size_t) npldynamicdevices * sizeof ( PLLoadableDevice ) ) ) == NULL ) ||
03036          ( ( loadable_driver_list = malloc( (size_t) npldynamicdevices * sizeof ( PLLoadableDriver ) ) ) == NULL ) )
03037     {
03038         fclose( fp_drvdb );
03039         plexit( "plInitDispatchTable: Insufficient memory" );
03040     }
03041 
03042     rewind( fp_drvdb );
03043 
03044     i    = 0;
03045     done = !( i < npldynamicdevices );
03046     while ( !done )
03047     {
03048         char *p = fgets( buf, BUFFER2_SIZE, fp_drvdb );
03049 
03050         if ( p == 0 )
03051         {
03052             done = 1;
03053             continue;
03054         }
03055 
03056         devnam  = strtok( buf, ":" );
03057         devdesc = strtok( 0, ":" );
03058         devtype = strtok( 0, ":" );
03059         driver  = strtok( 0, ":" );
03060         seqstr  = strtok( 0, ":" );
03061         tag     = strtok( 0, "\n" );
03062 
03063         if ( devnam == NULL || devdesc == NULL || devtype == NULL || driver == NULL ||
03064              seqstr == NULL || tag == NULL )
03065         {
03066             continue; // Ill-formatted line, most probably not a valid driver information file
03067         }
03068 
03069         seq = atoi( seqstr );
03070 
03071         n = npldrivers++;
03072 
03073         if ( ( dispatch_table[n] = malloc( sizeof ( PLDispatchTable ) ) ) == NULL )
03074         {
03075             fclose( fp_drvdb );
03076             plexit( "plInitDispatchTable: Insufficient memory" );
03077         }
03078 
03079         // Fill in the dispatch table entries.
03080         dispatch_table[n]->pl_MenuStr  = plstrdup( devdesc );
03081         dispatch_table[n]->pl_DevName  = plstrdup( devnam );
03082         dispatch_table[n]->pl_type     = atoi( devtype );
03083         dispatch_table[n]->pl_seq      = seq;
03084         dispatch_table[n]->pl_init     = 0;
03085         dispatch_table[n]->pl_line     = 0;
03086         dispatch_table[n]->pl_polyline = 0;
03087         dispatch_table[n]->pl_eop      = 0;
03088         dispatch_table[n]->pl_bop      = 0;
03089         dispatch_table[n]->pl_tidy     = 0;
03090         dispatch_table[n]->pl_state    = 0;
03091         dispatch_table[n]->pl_esc      = 0;
03092 
03093         // Add a record to the loadable device list
03094         loadable_device_list[i].devnam      = plstrdup( devnam );
03095         loadable_device_list[i].description = plstrdup( devdesc );
03096         loadable_device_list[i].drvnam      = plstrdup( driver );
03097         loadable_device_list[i].tag         = plstrdup( tag );
03098 
03099         // Now see if this driver has been seen before.  If not, add a driver
03100         // entry for it.
03101         driver_found = 0;
03102         for ( j = 0; j < nloadabledrivers; j++ )
03103             if ( strcmp( driver, loadable_driver_list[j].drvnam ) == 0 )
03104             {
03105                 driver_found = 1;
03106                 break;
03107             }
03108 
03109         if ( !driver_found )
03110         {
03111             loadable_driver_list[nloadabledrivers].drvnam = plstrdup( driver );
03112             loadable_driver_list[nloadabledrivers].dlhand = 0;
03113             nloadabledrivers++;
03114         }
03115 
03116         loadable_device_list[i].drvidx = j;
03117 
03118         // Get ready for next loadable device spec
03119         i++;
03120     }
03121 
03122 // RML: close fp_drvdb
03123     fclose( fp_drvdb );
03124 
03125 #endif
03126 
03127     if ( npldrivers == 0 )
03128     {
03129         npldynamicdevices = 0;
03130         plexit( "No device drivers found - please check the environment variable PLPLOT_DRV_DIR" );
03131     }
03132 
03133 // Finally, we need to sort the list into presentation order, based on the
03134 // sequence number in the dispatch ttable entries.
03135 
03136     qsort( dispatch_table, (size_t) npldrivers, sizeof ( PLDispatchTable* ),
03137         plDispatchSequencer );
03138 }
03139 
03140 //--------------------------------------------------------------------------
03141 // void plSelectDev()
03142 //
03143 // If the user has not already specified the output device, or the
03144 // one specified is either: (a) not available, (b) "?", or (c) NULL, the
03145 // user is prompted for it.
03146 //
03147 // Prompting quits after 10 unsuccessful tries in case the user has
03148 // run the program in the background with insufficient input.
03149 //--------------------------------------------------------------------------
03150 
03151 static void
03152 plSelectDev()
03153 {
03154     int dev, i, count;
03155     size_t length;
03156     char response[80];
03157     char   * devname_env;
03158 
03159 // If device name is not already specified, try to get it from environment
03160 
03161     if ( plsc->DevName[0] == '\0' )
03162     {
03163         devname_env = getenv( "PLPLOT_DEV" );
03164         if ( devname_env )
03165         {
03166             strncpy( plsc->DevName, devname_env, sizeof ( plsc->DevName ) - 1 );
03167             plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0';
03168         }
03169     }
03170 
03171 // Device name already specified.  See if it is valid.
03172 
03173     if ( *( plsc->DevName ) != '\0' && *( plsc->DevName ) != '?' )
03174     {
03175         length = strlen( plsc->DevName );
03176         for ( i = 0; i < npldrivers; i++ )
03177         {
03178             if ( ( *plsc->DevName == *dispatch_table[i]->pl_DevName ) &&
03179                  ( strncmp( plsc->DevName,
03180                        dispatch_table[i]->pl_DevName, length ) == 0 ) )
03181                 break;
03182         }
03183         if ( i < npldrivers )
03184         {
03185             plsc->device = i + 1;
03186             return;
03187         }
03188         else
03189         {
03190             fprintf( stderr, "Requested device %s not available\n",
03191                 plsc->DevName );
03192         }
03193     }
03194 
03195     dev   = 0;
03196     count = 0;
03197 
03198     if ( npldrivers == 1 )
03199         dev = 1;
03200 
03201 // User hasn't specified it correctly yet, so we prompt
03202 
03203     while ( dev < 1 || dev > npldrivers )
03204     {
03205         fprintf( stdout, "\nPlotting Options:\n" );
03206         for ( i = 0; i < npldrivers; i++ )
03207         {
03208             fprintf( stdout, " <%2d> %-10s %s\n", i + 1,
03209                 dispatch_table[i]->pl_DevName,
03210                 dispatch_table[i]->pl_MenuStr );
03211         }
03212         if ( ipls == 0 )
03213             fprintf( stdout, "\nEnter device number or keyword: " );
03214         else
03215             fprintf( stdout, "\nEnter device number or keyword (stream %d): ",
03216                 (int) ipls );
03217 
03218         plio_fgets( response, sizeof ( response ), stdin );
03219 
03220         // First check to see if device keyword was entered.
03221         // Final "\n" in response messes things up, so ignore it.
03222 
03223         length = strlen( response );
03224         if ( *( response - 1 + length ) == '\n' )
03225             length--;
03226 
03227         for ( i = 0; i < npldrivers; i++ )
03228         {
03229             if ( !strncmp( response, dispatch_table[i]->pl_DevName,
03230                      (unsigned int) length ) )
03231                 break;
03232         }
03233         if ( i < npldrivers )
03234         {
03235             dev = i + 1;
03236         }
03237         else
03238         {
03239             if ( ( dev = atoi( response ) ) < 1 )
03240             {
03241                 fprintf( stdout, "\nInvalid device: %s", response );
03242                 dev = 0;
03243             }
03244         }
03245         if ( count++ > 10 )
03246             plexit( "plSelectDev: Too many tries." );
03247     }
03248     plsc->device = dev;
03249     strcpy( plsc->DevName, dispatch_table[dev - 1]->pl_DevName );
03250 }
03251 
03252 //--------------------------------------------------------------------------
03253 // void plLoadDriver()
03254 //
03255 // Make sure the selected driver is loaded.  Static drivers are already
03256 // loaded, but if the user selected a dynamically loadable driver, we may
03257 // have to take care of that now.
03258 //--------------------------------------------------------------------------
03259 
03260 static void
03261 plLoadDriver( void )
03262 {
03263 #ifdef ENABLE_DYNDRIVERS
03264     int i, drvidx;
03265     char sym[BUFFER_SIZE];
03266     char *tag;
03267 
03268     int n = plsc->device - 1;
03269     PLDispatchTable  *dev    = dispatch_table[n];
03270     PLLoadableDriver *driver = 0;
03271 
03272 // If the dispatch table is already filled in, then either the device was
03273 // linked in statically, or else perhaps it was already loaded.  In either
03274 // case, we have nothing left to do.
03275     if ( dev->pl_init )
03276         return;
03277 
03278     pldebug( "plLoadDriver", "Device not loaded!\n" );
03279 
03280 // Now search through the list of loadable devices, looking for the record
03281 // that corresponds to the requested device.
03282     for ( i = 0; i < npldynamicdevices; i++ )
03283         if ( strcmp( dev->pl_DevName, loadable_device_list[i].devnam ) == 0 )
03284             break;
03285 
03286 // If we couldn't find such a record, then there is some sort of internal
03287 // logic flaw since plSelectDev is supposed to only select a valid device.
03288 //
03289     if ( i == npldynamicdevices )
03290     {
03291         fprintf( stderr, "No such device: %s.\n", dev->pl_DevName );
03292         plexit( "plLoadDriver detected device logic screwup" );
03293     }
03294 
03295 // Note the device tag, and the driver index. Note that a given driver could
03296 // supply multiple devices, each with a unique tag to distinguish the driver
03297 // entry points for the different supported devices.
03298     tag    = loadable_device_list[i].tag;
03299     drvidx = loadable_device_list[i].drvidx;
03300 
03301     pldebug( "plLoadDriver", "tag=%s, drvidx=%d\n", tag, drvidx );
03302 
03303     driver = &loadable_driver_list[drvidx];
03304 
03305 // Load the driver if it hasn't been loaded yet.
03306     if ( !driver->dlhand )
03307     {
03308         char drvspec[ DRVSPEC_SIZE ];
03309 #if defined ( LTDL_WIN32 ) || defined ( __CYGWIN__ )
03310         snprintf( drvspec, DRVSPEC_SIZE, "%s", driver->drvnam );
03311 #else
03312         snprintf( drvspec, DRVSPEC_SIZE, "%s/%s", plGetDrvDir(), driver->drvnam );
03313 #endif  // LTDL_WIN32
03314 
03315         pldebug( "plLoadDriver", "Trying to load %s on %s\n",
03316             driver->drvnam, drvspec );
03317 
03318         driver->dlhand = lt_dlopenext( drvspec );
03319 
03320         // A few of our drivers do not depend on other libraries.  So
03321         // allow them to be completely removed by plend to give clean
03322         // valgrind results.  However, the (large) remainder of our
03323         // drivers do depend on other libraries so mark them resident
03324         // to prevent problems with atexit handlers / library
03325         // reinitialisation such as those seen with qt and cairo
03326         // drivers.
03327         if ( !( strcmp( driver->drvnam, "mem" ) == 0 ||
03328                 strcmp( driver->drvnam, "null" ) == 0 ||
03329                 strcmp( driver->drvnam, "plmeta" ) == 0 ||
03330                 strcmp( driver->drvnam, "ps" ) == 0 ||
03331                 strcmp( driver->drvnam, "svg" ) == 0 ||
03332                 strcmp( driver->drvnam, "xfig" ) == 0 ) )
03333             lt_dlmakeresident( driver->dlhand );
03334     }
03335 
03336 // If it still isn't loaded, then we're doomed.
03337     if ( !driver->dlhand )
03338     {
03339         pldebug( "plLoadDriver", "lt_dlopenext failed because of "
03340             "the following reason:\n%s\n", lt_dlerror() );
03341         fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam );
03342         plexit( "Unable to load driver" );
03343     }
03344 
03345 // Now we are ready to ask the driver's device dispatch init function to
03346 // initialize the entries in the dispatch table.
03347 
03348     snprintf( sym, BUFFER_SIZE, "plD_dispatch_init_%s", tag );
03349     {
03350         PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym );
03351         if ( !dispatch_init )
03352         {
03353             fprintf( stderr,
03354                 "Unable to locate dispatch table initialization function for driver: %s.\n",
03355                 driver->drvnam );
03356             return;
03357         }
03358 
03359         ( *dispatch_init )( dev );
03360     }
03361 #endif
03362 }
03363 
03364 //--------------------------------------------------------------------------
03365 // void plfontld()
03366 //
03367 // Load specified font set.
03368 //--------------------------------------------------------------------------
03369 
03370 void
03371 c_plfontld( PLINT ifont )
03372 {
03373     if ( ifont != 0 )
03374         ifont = 1;
03375 
03376     if ( plsc->level > 0 )
03377         plfntld( ifont );
03378     else
03379         initfont = ifont;
03380 }
03381 
03382 //--------------------------------------------------------------------------
03383 // void plreplot()
03384 //
03385 // Replays contents of plot buffer to current device/file.
03386 //--------------------------------------------------------------------------
03387 
03388 void
03389 c_plreplot( void )
03390 {
03391 #ifdef BUFFERED_FILE
03392     if ( plsc->plbufFile != NULL )
03393     {
03394 #else
03395     if ( plsc->plbuf_buffer != NULL )
03396     {
03397 #endif
03398         plRemakePlot( plsc );
03399     }
03400     else
03401     {
03402         plwarn( "plreplot: plot buffer not available" );
03403     }
03404 }
03405 
03406 //--------------------------------------------------------------------------
03407 // void plgFileDevs()
03408 //
03409 // Returns a list of file-oriented device names and their menu strings,
03410 // for use in a graphical interface.  The caller must allocate enough
03411 // space for (*p_menustr) and (*p_devname) to hold a pointer for each
03412 // device -- 20 or so is plenty.  E.g. char *menustr[20].  The size of
03413 // these arrays should be passed in *p_ndev, which, on exit, holds the
03414 // number of devices actually present.
03415 //--------------------------------------------------------------------------
03416 
03417 void
03418 plgFileDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev )
03419 {
03420     plgdevlst( *p_menustr, *p_devname, p_ndev, 0 );
03421 }
03422 
03423 //--------------------------------------------------------------------------
03424 // void plgDevs()
03425 //
03426 // Like plgFileDevs(), but returns names and menu strings for all devices.
03427 //--------------------------------------------------------------------------
03428 
03429 void
03430 plgDevs( const char ***p_menustr, const char ***p_devname, int *p_ndev )
03431 {
03432     plgdevlst( *p_menustr, *p_devname, p_ndev, -1 );
03433 }
03434 
03435 static void
03436 plgdevlst( const char **p_menustr, const char **p_devname, int *p_ndev, int type )
03437 {
03438     int i, j;
03439 
03440     pllib_init();
03441 
03442     for ( i = j = 0; i < npldrivers; i++ )
03443     {
03444         if ( type < 0 || dispatch_table[i]->pl_type == type )
03445         {
03446             p_menustr[j] = dispatch_table[i]->pl_MenuStr;
03447             p_devname[j] = dispatch_table[i]->pl_DevName;
03448             if ( ++j + 1 >= *p_ndev )
03449             {
03450                 plwarn( "plgdevlst:  too many devices" );
03451                 break;
03452             }
03453         }
03454     }
03455     p_menustr[j] = NULL;
03456     p_devname[j] = NULL;
03457     *p_ndev      = j;
03458 }
03459 
03460 //--------------------------------------------------------------------------
03461 //  Various external access routines.
03462 //--------------------------------------------------------------------------
03463 
03464 // Get output device parameters.
03465 
03466 void
03467 c_plgpage( PLFLT *p_xp, PLFLT *p_yp,
03468            PLINT *p_xleng, PLINT *p_yleng, PLINT *p_xoff, PLINT *p_yoff )
03469 {
03470     *p_xp    = plsc->xdpi;
03471     *p_yp    = plsc->ydpi;
03472     *p_xleng = plsc->xlength;
03473     *p_yleng = plsc->ylength;
03474     *p_xoff  = plsc->xoffset;
03475     *p_yoff  = plsc->yoffset;
03476 }
03477 
03478 // Set output device parameters.  Usually ignored by the driver.
03479 
03480 void
03481 c_plspage( PLFLT xp, PLFLT yp, PLINT xleng, PLINT yleng, PLINT xoff, PLINT yoff )
03482 {
03483     if ( plsc->level > 0 )
03484         plwarn( "calling plspage() after plinit() may give unpredictable results" );
03485 
03486     if ( xp )
03487         plsc->xdpi = xp;
03488     if ( yp )
03489         plsc->ydpi = yp;
03490 
03491     if ( xleng )
03492         plsc->xlength = xleng;
03493     if ( yleng )
03494         plsc->ylength = yleng;
03495 
03496     if ( xoff )
03497         plsc->xoffset = xoff;
03498     if ( yoff )
03499         plsc->yoffset = yoff;
03500 
03501     plsc->pageset = 1;
03502 }
03503 
03504 // Set the number of subwindows in x and y
03505 
03506 void
03507 c_plssub( PLINT nx, PLINT ny )
03508 {
03509     if ( nx > 0 )
03510         plsc->nsubx = nx;
03511     if ( ny > 0 )
03512         plsc->nsuby = ny;
03513 
03514 // Force a page advance
03515 
03516     if ( plsc->level > 0 )
03517     {
03518         plP_subpInit();
03519 //AWI   plP_eop();
03520 //      plP_bop();
03521     }
03522 }
03523 
03524 // Set the device (keyword) name
03525 
03526 void
03527 c_plsdev( const char *devname )
03528 {
03529     if ( plsc->level > 0 )
03530     {
03531         plwarn( "plsdev: Must be called before plinit." );
03532         return;
03533     }
03534     if ( devname != NULL )
03535     {
03536         strncpy( plsc->DevName, devname, sizeof ( plsc->DevName ) - 1 );
03537         plsc->DevName[sizeof ( plsc->DevName ) - 1] = '\0';
03538     }
03539 }
03540 
03541 // Get the current device (keyword) name
03542 // Note: you MUST have allocated space for this (80 characters is safe)
03543 
03544 void
03545 c_plgdev( char *p_dev )
03546 {
03547     strcpy( p_dev, plsc->DevName );
03548 }
03549 
03550 // Set the memory area to be plotted (with the 'mem' driver) as the 'dev'
03551 // member of the stream structure.  Also set the number
03552 // of pixels in the memory passed in in 'plotmem'.
03553 // Plotmem is a block of memory maxy by maxx by 3 bytes long, say:
03554 // 480 x 640 x 3 (Y, X, RGB)
03555 //
03556 // This memory will be freed by the user!
03557 //
03558 
03559 void
03560 c_plsmem( PLINT maxx, PLINT maxy, void *plotmem )
03561 {
03562     plsc->dev           = plotmem;
03563     plsc->dev_mem_alpha = 0;
03564     plP_setphy( 0, maxx, 0, maxy );
03565 }
03566 
03567 // Same as plsmem, but the buffer is (Y, X, RGBA)
03568 
03569 void
03570 c_plsmema( PLINT maxx, PLINT maxy, void *plotmem )
03571 {
03572     plsc->dev           = plotmem;
03573     plsc->dev_mem_alpha = 1;
03574     plP_setphy( 0, maxx, 0, maxy );
03575 }
03576 
03577 // Get the current stream pointer
03578 
03579 void
03580 plgpls( PLStream **p_pls )
03581 {
03582     *p_pls = plsc;
03583 }
03584 
03585 // Get the (current) run level.
03586 // Valid settings are:
03587 //   0  uninitialized
03588 //   1  initialized
03589 //   2  viewport defined
03590 //   3  world coords defined
03591 //
03592 
03593 void
03594 c_plglevel( PLINT *p_level )
03595 {
03596     *p_level = plsc->level;
03597 }
03598 
03599 // Set the function pointer for the keyboard event handler
03600 
03601 void
03602 plsKeyEH( void ( *KeyEH )( PLGraphicsIn *, void *, int * ),
03603           void *KeyEH_data )
03604 {
03605     plsc->KeyEH      = KeyEH;
03606     plsc->KeyEH_data = KeyEH_data;
03607 }
03608 
03609 // Set the function pointer for the (mouse) button event handler
03610 
03611 void
03612 plsButtonEH( void ( *ButtonEH )( PLGraphicsIn *, void *, int * ),
03613              void *ButtonEH_data )
03614 {
03615     plsc->ButtonEH      = ButtonEH;
03616     plsc->ButtonEH_data = ButtonEH_data;
03617 }
03618 
03619 // Sets an optional user bop handler.
03620 
03621 void
03622 plsbopH( void ( *handler )( void *, int * ), void *handler_data )
03623 {
03624     plsc->bop_handler = handler;
03625     plsc->bop_data    = handler_data;
03626 }
03627 
03628 // Sets an optional user eop handler.
03629 
03630 void
03631 plseopH( void ( *handler )( void *, int * ), void *handler_data )
03632 {
03633     plsc->eop_handler = handler;
03634     plsc->eop_data    = handler_data;
03635 }
03636 
03637 // Set the variables to be used for storing error info
03638 
03639 void
03640 plsError( PLINT *errcode, char *errmsg )
03641 {
03642     if ( errcode != NULL )
03643         plsc->errcode = errcode;
03644 
03645     if ( errmsg != NULL )
03646         plsc->errmsg = errmsg;
03647 }
03648 
03649 // Set orientation.  Must be done before calling plinit.
03650 
03651 void
03652 c_plsori( PLINT ori )
03653 {
03654     plsdiori( (PLFLT) ori );
03655 }
03656 
03657 //
03658 // Set pen width.  Can be done any time, but before calling plinit is best
03659 // since otherwise it may be volatile (i.e. reset on next page advance).
03660 // If width < 0 or is unchanged by the call, nothing is done.
03661 //
03662 
03663 void
03664 c_plwidth( PLFLT width )
03665 {
03666     if ( width != plsc->width && width >= 0. )
03667     {
03668         plsc->width = width;
03669 
03670         if ( plsc->level > 0 )
03671         {
03672             if ( !plsc->widthlock )
03673                 plP_state( PLSTATE_WIDTH );
03674         }
03675     }
03676 }
03677 
03678 // Set the output file pointer
03679 
03680 void
03681 plgfile( FILE **p_file )
03682 {
03683     *p_file = plsc->OutFile;
03684 }
03685 
03686 // Get the output file pointer
03687 
03688 void
03689 plsfile( FILE *file )
03690 {
03691     plsc->OutFile = file;
03692 }
03693 
03694 // Get the (current) output file name.  Must be preallocated to >=80 bytes
03695 // Beyond that, I truncate it.  You have been warned.
03696 
03697 void
03698 c_plgfnam( char *fnam )
03699 {
03700     if ( fnam == NULL )
03701     {
03702         plabort( "filename string must be preallocated to >=80 bytes" );
03703         return;
03704     }
03705 
03706     *fnam = '\0';
03707     if ( plsc->FileName != NULL )
03708     {
03709         strncpy( fnam, plsc->FileName, 79 );
03710         fnam[79] = '\0';
03711     }
03712 }
03713 
03714 // Set the output file name.
03715 
03716 void
03717 c_plsfnam( const char *fnam )
03718 {
03719     plP_sfnam( plsc, fnam );
03720 }
03721 
03722 // Set the pause (on end-of-page) status
03723 
03724 void
03725 c_plspause( PLINT p )
03726 {
03727     plsc->nopause = !p;
03728 }
03729 
03730 // Set the floating point precision (in number of places) in numeric labels.
03731 
03732 void
03733 c_plprec( PLINT setp, PLINT prec )
03734 {
03735     plsc->setpre = setp;
03736     plsc->precis = prec;
03737 }
03738 
03739 // Get the floating point precision (in number of places) in numeric labels.
03740 
03741 void
03742 plP_gprec( PLINT *p_setp, PLINT *p_prec )
03743 {
03744     *p_setp = plsc->setpre;
03745     *p_prec = plsc->precis;
03746 }
03747 
03748 const char *
03749 plP_gtimefmt()
03750 {
03751     return (const char *) plsc->timefmt;
03752 }
03753 
03754 //
03755 // Set the escape character for text strings.
03756 // From C you can pass as a character, from Fortran it needs to be the decimal
03757 // ASCII value.  Only selected characters are allowed to prevent the user from
03758 // shooting himself in the foot (a '\' isn't allowed since it conflicts with
03759 // C's use of backslash as a character escape).
03760 //
03761 
03762 void
03763 c_plsesc( char esc )
03764 {
03765     switch ( esc )
03766     {
03767     case '!':                   // ASCII 33
03768     case '#':                   // ASCII 35
03769     case '$':                   // ASCII 36
03770     case '%':                   // ASCII 37
03771     case '&':                   // ASCII 38
03772     case '*':                   // ASCII 42
03773     case '@':                   // ASCII 64
03774     case '^':                   // ASCII 94
03775     case '~':                   // ASCII 126
03776         plsc->esc = esc;
03777         break;
03778 
03779     default:
03780         plwarn( "plsesc: Invalid escape character, ignoring." );
03781     }
03782 }
03783 
03784 // Get the escape character for text strings.
03785 
03786 void
03787 plgesc( char *p_esc )
03788 {
03789     if ( plsc->esc == '\0' )
03790         plsc->esc = '#';
03791 
03792     *p_esc = plsc->esc;
03793 }
03794 
03795 // Set the FCI (font characterization integer) for unicode-enabled device
03796 // drivers.
03797 //
03798 void
03799 c_plsfci( PLUNICODE fci )
03800 {
03801     // Always mark FCI as such.
03802     plsc->fci = fci | PL_FCI_MARK;
03803 }
03804 
03805 // Get the FCI (font characterization integer) for unicode-enabled device
03806 // drivers.
03807 //
03808 void
03809 c_plgfci( PLUNICODE *p_fci )
03810 {
03811     // Always mark FCI as such.
03812     *p_fci = plsc->fci | PL_FCI_MARK;
03813 }
03814 // Store hex digit value shifted to the left by hexdigit hexadecimal digits
03815 // into pre-existing FCI.
03816 //
03817 void
03818 plP_hex2fci( unsigned char hexdigit, unsigned char hexpower, PLUNICODE *pfci )
03819 {
03820     PLUNICODE mask;
03821     hexpower = hexpower & PL_FCI_HEXPOWER_MASK;
03822     mask     = ~( ( (PLUNICODE) PL_FCI_HEXDIGIT_MASK ) << ( (PLUNICODE) 4 * hexpower ) );
03823     *pfci    = *pfci & mask;
03824     mask     = ( ( (PLUNICODE) ( hexdigit & PL_FCI_HEXDIGIT_MASK ) ) << ( 4 * hexpower ) );
03825     *pfci    = *pfci | mask;
03826 }
03827 
03828 // Retrieve hex digit value from FCI that is masked out and shifted to the
03829 // right by hexpower hexadecimal digits.
03830 void
03831 plP_fci2hex( PLUNICODE fci, unsigned char *phexdigit, unsigned char hexpower )
03832 {
03833     PLUNICODE mask;
03834     hexpower   = hexpower & PL_FCI_HEXPOWER_MASK;
03835     mask       = ( ( (PLUNICODE) PL_FCI_HEXPOWER_MASK ) << ( (PLUNICODE) ( 4 * hexpower ) ) );
03836     *phexdigit = (unsigned char) ( ( fci & mask ) >>
03837                                    ( (PLUNICODE) ( 4 * hexpower ) ) );
03838 }
03839 
03840 // Get the current library version number
03841 // Note: you MUST have allocated space for this (80 characters is safe)
03842 void
03843 c_plgver( char *p_ver )
03844 {
03845     strcpy( p_ver, PLPLOT_VERSION );
03846 }
03847 
03848 // Set inferior X window
03849 
03850 void
03851 plsxwin( PLINT window_id )
03852 {
03853     plsc->window_id = window_id;
03854 }
03855 
03856 //--------------------------------------------------------------------------
03857 //  These set/get information for family files, and may be called prior
03858 //  to plinit to set up the necessary parameters.  Arguments:
03859 //
03860 //      fam     familying flag (boolean)
03861 //      num     member number
03862 //      bmax    maximum member size
03863 //--------------------------------------------------------------------------
03864 
03865 // Get family file parameters
03866 
03867 void
03868 c_plgfam( PLINT *p_fam, PLINT *p_num, PLINT *p_bmax )
03869 {
03870     *p_fam  = plsc->family;
03871     *p_num  = plsc->member;
03872     *p_bmax = plsc->bytemax;
03873 }
03874 
03875 // Set family file parameters
03876 
03877 void
03878 c_plsfam( PLINT fam, PLINT num, PLINT bmax )
03879 {
03880     if ( plsc->level > 0 )
03881         plwarn( "plsfam: Must be called before plinit." );
03882 
03883     if ( fam >= 0 )
03884         plsc->family = fam;
03885     if ( num >= 0 )
03886         plsc->member = num;
03887     if ( bmax >= 0 )
03888         plsc->bytemax = bmax;
03889 }
03890 
03891 // Advance to the next family file on the next new page
03892 
03893 void
03894 c_plfamadv( void )
03895 {
03896     plsc->famadv = 1;
03897 }
03898 
03899 //--------------------------------------------------------------------------
03900 //  Interface routines for axis labling parameters.
03901 //  See pldtik.c for more info.
03902 //--------------------------------------------------------------------------
03903 
03904 // Get x axis labeling parameters
03905 
03906 void
03907 c_plgxax( PLINT *p_digmax, PLINT *p_digits )
03908 {
03909     *p_digmax = plsc->xdigmax;
03910     *p_digits = plsc->xdigits;
03911 }
03912 
03913 // Set x axis labeling parameters
03914 
03915 void
03916 c_plsxax( PLINT digmax, PLINT digits )
03917 {
03918     plsc->xdigmax = digmax;
03919     plsc->xdigits = digits;
03920 }
03921 
03922 // Get y axis labeling parameters
03923 
03924 void
03925 c_plgyax( PLINT *p_digmax, PLINT *p_digits )
03926 {
03927     *p_digmax = plsc->ydigmax;
03928     *p_digits = plsc->ydigits;
03929 }
03930 
03931 // Set y axis labeling parameters
03932 
03933 void
03934 c_plsyax( PLINT digmax, PLINT digits )
03935 {
03936     plsc->ydigmax = digmax;
03937     plsc->ydigits = digits;
03938 }
03939 
03940 // Get z axis labeling parameters
03941 
03942 void
03943 c_plgzax( PLINT *p_digmax, PLINT *p_digits )
03944 {
03945     *p_digmax = plsc->zdigmax;
03946     *p_digits = plsc->zdigits;
03947 }
03948 
03949 // Set z axis labeling parameters
03950 
03951 void
03952 c_plszax( PLINT digmax, PLINT digits )
03953 {
03954     plsc->zdigmax = digmax;
03955     plsc->zdigits = digits;
03956 }
03957 
03958 // Get character default height and current (scaled) height
03959 
03960 void
03961 c_plgchr( PLFLT *p_def, PLFLT *p_ht )
03962 {
03963     *p_def = plsc->chrdef;
03964     *p_ht  = plsc->chrht;
03965 }
03966 
03967 // Get viewport boundaries in normalized device coordinates
03968 
03969 void
03970 c_plgvpd( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
03971 {
03972     *p_xmin = plsc->vpdxmi;
03973     *p_xmax = plsc->vpdxma;
03974     *p_ymin = plsc->vpdymi;
03975     *p_ymax = plsc->vpdyma;
03976 }
03977 
03978 // Get viewport boundaries in world coordinates
03979 
03980 void
03981 c_plgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
03982 {
03983     *p_xmin = plsc->vpwxmi;
03984     *p_xmax = plsc->vpwxma;
03985     *p_ymin = plsc->vpwymi;
03986     *p_ymax = plsc->vpwyma;
03987 }
03988 
03989 // Get the viewport boundaries in world coordinates, expanded slightly
03990 void
03991 plP_xgvpw( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
03992 {
03993     PLFLT dx, dy;
03994 
03995     dx = ( plsc->vpwxma - plsc->vpwxmi ) * 1.0e-5;
03996     dy = ( plsc->vpwyma - plsc->vpwymi ) * 1.0e-5;
03997 
03998     // The plot window is made slightly larger than requested so that
03999     // the end limits will be on the graph
04000 
04001     *p_xmin = plsc->vpwxmi - dx;
04002     *p_xmax = plsc->vpwxma + dx;
04003     *p_ymin = plsc->vpwymi - dy;
04004     *p_ymax = plsc->vpwyma + dy;
04005 }
04006 
04007 //--------------------------------------------------------------------------
04008 //  These should not be called by the user.
04009 //--------------------------------------------------------------------------
04010 
04011 // Get x-y domain in world coordinates for 3d plots
04012 
04013 void
04014 plP_gdom( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax )
04015 {
04016     *p_xmin = plsc->domxmi;
04017     *p_xmax = plsc->domxma;
04018     *p_ymin = plsc->domymi;
04019     *p_ymax = plsc->domyma;
04020 }
04021 
04022 // Get vertical (z) scale parameters for 3-d plot
04023 
04024 void
04025 plP_grange( PLFLT *p_zscl, PLFLT *p_zmin, PLFLT *p_zmax )
04026 {
04027     *p_zscl = plsc->zzscl;
04028     *p_zmin = plsc->ranmi;
04029     *p_zmax = plsc->ranma;
04030 }
04031 
04032 // Get parameters used in 3d plots
04033 
04034 void
04035 plP_gw3wc( PLFLT *p_dxx, PLFLT *p_dxy, PLFLT *p_dyx, PLFLT *p_dyy, PLFLT *p_dyz )
04036 {
04037     *p_dxx = plsc->cxx;
04038     *p_dxy = plsc->cxy;
04039     *p_dyx = plsc->cyx;
04040     *p_dyy = plsc->cyy;
04041     *p_dyz = plsc->cyz;
04042 }
04043 
04044 // Get clip boundaries in physical coordinates
04045 
04046 void
04047 plP_gclp( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax )
04048 {
04049     *p_ixmin = plsc->clpxmi;
04050     *p_ixmax = plsc->clpxma;
04051     *p_iymin = plsc->clpymi;
04052     *p_iymax = plsc->clpyma;
04053 }
04054 
04055 // Set clip boundaries in physical coordinates
04056 
04057 void
04058 plP_sclp( PLINT ixmin, PLINT ixmax, PLINT iymin, PLINT iymax )
04059 {
04060     plsc->clpxmi = ixmin;
04061     plsc->clpxma = ixmax;
04062     plsc->clpymi = iymin;
04063     plsc->clpyma = iymax;
04064 }
04065 
04066 // Get physical device limits in physical coordinates
04067 
04068 void
04069 plP_gphy( PLINT *p_ixmin, PLINT *p_ixmax, PLINT *p_iymin, PLINT *p_iymax )
04070 {
04071     *p_ixmin = plsc->phyxmi;
04072     *p_ixmax = plsc->phyxma;
04073     *p_iymin = plsc->phyymi;
04074     *p_iymax = plsc->phyyma;
04075 }
04076 
04077 // Get number of subpages on physical device and current subpage
04078 
04079 void
04080 plP_gsub( PLINT *p_nx, PLINT *p_ny, PLINT *p_cs )
04081 {
04082     *p_nx = plsc->nsubx;
04083     *p_ny = plsc->nsuby;
04084     *p_cs = plsc->cursub;
04085 }
04086 
04087 // Set number of subpages on physical device and current subpage
04088 
04089 void
04090 plP_ssub( PLINT nx, PLINT ny, PLINT cs )
04091 {
04092     plsc->nsubx  = nx;
04093     plsc->nsuby  = ny;
04094     plsc->cursub = cs;
04095 }
04096 
04097 // Get number of pixels to a millimeter
04098 
04099 void
04100 plP_gpixmm( PLFLT *p_x, PLFLT *p_y )
04101 {
04102     *p_x = plsc->xpmm;
04103     *p_y = plsc->ypmm;
04104 }
04105 
04106 // All the drivers call this to set physical pixels/mm.
04107 
04108 void
04109 plP_setpxl( PLFLT xpmm, PLFLT ypmm )
04110 {
04111     plsc->xpmm = xpmm;
04112     plsc->ypmm = ypmm;
04113     plsc->umx  = (PLINT) ( 1000.0 / plsc->xpmm );
04114     plsc->umy  = (PLINT) ( 1000.0 / plsc->ypmm );
04115 }
04116 
04117 // Sets up physical limits of plotting device.
04118 
04119 void
04120 plP_setphy( PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax )
04121 {
04122     if ( xmin > xmax || ymin > ymax )
04123         plexit( "plP_setphy: device minima must not exceed maxima" );
04124 
04125     plsc->phyxmi  = xmin;
04126     plsc->phyxma  = xmax;
04127     plsc->phyymi  = ymin;
04128     plsc->phyyma  = ymax;
04129     plsc->phyxlen = xmax - xmin;
04130     plsc->phyylen = ymax - ymin;
04131 }
04132 
04133 //--------------------------------------------------------------------------
04134 // void c_plscompression()
04135 //
04136 // Set compression.
04137 // Has to be done before plinit.
04138 //--------------------------------------------------------------------------
04139 
04140 void
04141 c_plscompression( PLINT compression )
04142 {
04143     if ( plsc->level <= 0 )
04144     {
04145         plsc->dev_compression = compression;
04146     }
04147 }
04148 
04149 //--------------------------------------------------------------------------
04150 // void c_plgcompression()
04151 //
04152 // Get compression
04153 //--------------------------------------------------------------------------
04154 
04155 void
04156 c_plgcompression( PLINT *compression )
04157 {
04158     *compression = plsc->dev_compression;
04159 }
04160 
04161 
04162 //--------------------------------------------------------------------------
04163 // void plP_getinitdriverlist()
04164 //
04165 // Check to see if a driver/stream has been initialised
04166 // Returns a space separated list of matches streams/drivers
04167 // If more than one stream uses the same device, then the device name
04168 // will be returned for each stream.
04169 // Caller must allocate enough memory for "names" to hold the answer.
04170 //--------------------------------------------------------------------------
04171 
04172 void
04173 plP_getinitdriverlist( char *names )
04174 {
04175     int i;
04176 
04177     for ( i = 0; i < PL_NSTREAMS; ++i )
04178     {
04179         if ( pls[i] != NULL )
04180         {
04181             if ( i == 0 )
04182                 strcpy( names, pls[i]->DevName );
04183             else
04184             {
04185                 strcat( names, " " );
04186                 strcat( names, pls[i]->DevName );
04187             }
04188         }
04189         else
04190             break;
04191     }
04192 }
04193 
04194 
04195 //--------------------------------------------------------------------------
04196 // PLINT plP_checkdriverinit()
04197 //
04198 // Checks from a list of given drivers which ones have been initialised
04199 // and returns the number of devices matching the list, or -1 if in error.
04200 // Effectively returns the number of streams matching the given stream.
04201 //--------------------------------------------------------------------------
04202 
04203 PLINT plP_checkdriverinit( char *names )
04204 {
04205     char  *buff;
04206     char  *tok = NULL;
04207     PLINT ret  = 0;                                     // set up return code to 0, the value if no devices match
04208 
04209     buff = (char *) malloc( (size_t) PL_NSTREAMS * 8 ); // Allocate enough memory for 8
04210                                                         // characters for each possible stream
04211 
04212     if ( buff != NULL )
04213     {
04214         memset( buff, 0, PL_NSTREAMS * 8 );     // Make sure we clear it
04215         plP_getinitdriverlist( buff );          // Get the list of initialised devices
04216 
04217         for ( tok = strtok( buff, " ," );       // Check each device against the "name"
04218               tok; tok = strtok( 0, " ," ) )    // supplied to the subroutine
04219         {
04220             if ( strstr( names, tok ) != NULL ) // Check to see if the device has been initialised
04221             {
04222                 ret++;                          // Bump the return code if it has
04223             }
04224         }
04225         free( buff );                // Clear up that memory we allocated
04226     }
04227     else
04228         ret = -1; // Error flag
04229 
04230     return ( ret );
04231 }
04232 
04233 
04234 //--------------------------------------------------------------------------
04235 // plP_image
04236 //
04237 // Author: Alessandro Mirone, Nov 2001
04238 //
04239 // Updated by Hezekiah Carty, Mar 2008.
04240 //   - Added support for pltr callback
04241 //   - Commented out the "dev_fastimg" rendering path
04242 //
04243 //--------------------------------------------------------------------------
04244 
04245 void
04246 plP_image( PLFLT *z, PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT dy,
04247            void ( *pltr )( PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer ), PLPointer pltr_data )
04248 {
04249     plsc->page_status = DRAWING;
04250 
04251     plimageslow( z, nx, ny, xmin, ymin, dx, dy, pltr, pltr_data );
04252 
04253     //
04254     // COMMENTED OUT by Hezekiah Carty, March 2008
04255     // The current dev_fastimg rendering method does not work as-is with
04256     // the plimagefr coordinate transform support.
04257     // This is hopefully temporary, until the dev_fastimg rendering
04258     // path can be updated to work with the new plimage internals.
04259     // Until then, all plimage* rendering is done by the plimageslow
04260     // rendering path.
04261     //
04262 #if 0   // BEGIN dev_fastimg COMMENT
04263     PLINT i, npts;
04264     short *xscl, *yscl;
04265     int plbuf_write;
04266 
04267     plsc->page_status = DRAWING;
04268 
04269     if ( plsc->dev_fastimg == 0 )
04270     {
04271         plimageslow( x, y, z, nx - 1, ny - 1,
04272             xmin, ymin, dx, dy, zmin, zmax );
04273         return;
04274     }
04275 
04276     if ( plsc->plbuf_write )
04277     {
04278         IMG_DT img_dt;
04279 
04280         img_dt.xmin = xmin;
04281         img_dt.ymin = ymin;
04282         img_dt.dx   = dx;
04283         img_dt.dy   = dy;
04284 
04285         plsc->dev_ix    = x;
04286         plsc->dev_iy    = y;
04287         plsc->dev_z     = z;
04288         plsc->dev_nptsX = nx;
04289         plsc->dev_nptsY = ny;
04290         plsc->dev_zmin  = zmin;
04291         plsc->dev_zmax  = zmax;
04292 
04293         plbuf_esc( plsc, PLESC_IMAGE, &img_dt );
04294     }
04295 
04296     // avoid re-saving plot buffer while in plP_esc()
04297     plbuf_write       = plsc->plbuf_write;
04298     plsc->plbuf_write = 0;
04299 
04300     npts = nx * ny;
04301     if ( plsc->difilt ) // isn't this odd? when replaying the plot buffer, e.g., when resizing the window, difilt() is caled again! the plot buffer should already contain the transformed data--it would save a lot of time! (and allow for differently oriented plots when in multiplot mode)
04302     {
04303         PLINT clpxmi, clpxma, clpymi, clpyma;
04304 
04305         if ( ( ( xscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) ||
04306              ( ( yscl = (short *) malloc( nx * ny * sizeof ( short ) ) ) == NULL ) )
04307         {
04308             plexit( "plP_image: Insufficient memory" );
04309         }
04310 
04311         for ( i = 0; i < npts; i++ )
04312         {
04313             xscl[i] = x[i];
04314             yscl[i] = y[i];
04315         }
04316         sdifilt( xscl, yscl, npts, &clpxmi, &clpxma, &clpymi, &clpyma );
04317         plsc->imclxmin = clpxmi;
04318         plsc->imclymin = clpymi;
04319         plsc->imclxmax = clpxma;
04320         plsc->imclymax = clpyma;
04321         grimage( xscl, yscl, z, nx, ny );
04322         free( xscl );
04323         free( yscl );
04324     }
04325     else
04326     {
04327         plsc->imclxmin = plsc->phyxmi;
04328         plsc->imclymin = plsc->phyymi;
04329         plsc->imclxmax = plsc->phyxma;
04330         plsc->imclymax = plsc->phyyma;
04331         grimage( x, y, z, nx, ny );
04332     }
04333     plsc->plbuf_write = plbuf_write;
04334 #endif  // END dev_fastimg COMMENT
04335 }
04336 
04337 //--------------------------------------------------------------------------
04338 // plstransform
04339 //
04340 // Set a universal coordinate transform function which will be applied to all
04341 // plotted items.
04342 //--------------------------------------------------------------------------
04343 void
04344 c_plstransform( void ( *coordinate_transform )( PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer ), PLPointer coordinate_transform_data )
04345 {
04346     plsc->coordinate_transform      = coordinate_transform;
04347     plsc->coordinate_transform_data = coordinate_transform_data;
04348 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines