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