• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

plcore.c

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

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1