From 60176b80396e64ca40259c176b4e96b548c924da Mon Sep 17 00:00:00 2001
From: Jim Dishaw <jim@dishaw.org>
Date: Tue, 2 Jun 2015 11:37:33 -0400
Subject: [PATCH] Code cleanup of warning and error messages and started to
 eliminate static global buffers

These changes were motivated to reduce the use of malloc() calls or large character arrays.

- Consolidated plwarn(), plabort(), plexit(), and associated functions into plerror.c
- Modified plwarn(), plabort(), and plexit() to use variable arguments
- Eliminated the use of allocating a temporary string buffer and using snprintf (or sprintf) to format an error/warning message before calling plwarn()
- Modified fprintf() calls that appeared to be warnings or errors to us plwarn() or plexit()
---
 drivers/aqt.c             |  14 +--
 drivers/cairo.c           |   8 +-
 drivers/linuxvga.c        |   3 +-
 drivers/pdf.c             |   9 +-
 drivers/plmeta.c          |   6 +-
 drivers/ps.c              |  19 ++--
 drivers/wxwidgets_dev.cpp |   4 +-
 drivers/xwin.c            |  20 ++--
 include/plplotP.h         |   6 +-
 src/CMakeLists.txt        |   1 +
 src/pdfutils.c            |   6 +-
 src/plargs.c              |  79 +++++++--------
 src/plbuf.c               |   6 +-
 src/plcore.c              |  45 ++++-----
 src/plctrl.c              | 253 +++++++---------------------------------------
 src/plerror.c             | 199 ++++++++++++++++++++++++++++++++++++
 src/plfill.c              |   2 +-
 src/plmap.c               |   2 +-
 src/plshade.c             |   2 +-
 src/plvect.c              |   2 +-
 20 files changed, 337 insertions(+), 349 deletions(-)
 create mode 100644 src/plerror.c

diff --git a/drivers/aqt.c b/drivers/aqt.c
index 4232650..6b93f2f 100644
--- a/drivers/aqt.c
+++ b/drivers/aqt.c
@@ -510,7 +510,7 @@ void get_cursor( PLStream *pls, PLGraphicsIn *gin )
     }
     else                // just return zeroes if we did not
     {
-        printf( "AquaTerm did not return a valid mouse location!\n" );
+        plwarn( "AquaTerm did not return a valid mouse location!\n" );
         gin->button = 0;
         gin->pX     = 0;
         gin->pY     = 0;
@@ -537,7 +537,7 @@ void proc_str( PLStream *pls, EscText *args )
 
     if ( args->unicode_array_len == 0 )
     {
-        printf( "Non unicode string passed to AquaTerm driver, ignoring\n" );
+        plwarn( "Non unicode string passed to AquaTerm driver, ignoring\n" );
         return;
     }
 
@@ -545,7 +545,7 @@ void proc_str( PLStream *pls, EscText *args )
 
     if ( args->unicode_array_len >= MAX_STRING_LEN )
     {
-        printf( "Sorry, the AquaTerm driver only handles strings of length < %d\n", MAX_STRING_LEN );
+        plwarn( "Sorry, the AquaTerm driver only handles strings of length < %d\n", MAX_STRING_LEN );
         return;
     }
 
@@ -693,7 +693,7 @@ NSMutableAttributedString  * create_string( const PLUNICODE *ucs4, int ucs4_len,
                 if ( ucs4[i] == (PLUNICODE) 'f' )       // font change
                 {
                     i++;
-                    printf( "hmm, unicode string apparently not following fci convention...\n" );
+                    plwarn( "hmm, unicode string apparently not following fci convention...\n" );
                 }
                 if ( ucs4[i] == (PLUNICODE) 'd' )       // Subscript
                 {
@@ -742,7 +742,7 @@ void set_font_and_size( NSMutableAttributedString * str, PLUNICODE fci, PLFLT fo
 
     if ( font == NULL )
     {
-        printf( "AquaTerm : Warning, could not find font given by fci = 0x%x\n", fci );
+        plwarn( "AquaTerm : Warning, could not find font given by fci = 0x%x\n", fci );
         font = "Helvetica";
     }
     /* font = "FreeSerif";	*//* force the font for debugging purposes */
@@ -788,12 +788,12 @@ void check_font_environment_variables( void )
 
             if ( end != NULL )
             {
-                printf( "Aquaterm : Warning, removing extension from font name : %s\n", new_font );
+                plwarn( "Aquaterm : Warning, removing extension from font name : %s\n", new_font );
                 *end = '\0';
             }
             if ( begin != NULL )
             {
-                printf( "AquaTerm : Warning, removing path from font name : %s\n", new_font );
+                plwarn( "AquaTerm : Warning, removing path from font name : %s\n", new_font );
                 new_font = begin + 1;
             }
 
diff --git a/drivers/cairo.c b/drivers/cairo.c
index 4afa908..b12e783 100644
--- a/drivers/cairo.c
+++ b/drivers/cairo.c
@@ -888,14 +888,14 @@ void proc_str( PLStream *pls, EscText *args )
     // Check that we got unicode, warning message and return if not
     if ( args->unicode_array_len == 0 )
     {
-        printf( "Non unicode string passed to a cairo driver, ignoring\n" );
+        plwarn( "Non unicode string passed to a cairo driver, ignoring\n" );
         return;
     }
 
     // Check that unicode string isn't longer then the max we allow
     if ( args->unicode_array_len >= MAX_STRING_LEN )
     {
-        printf( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
+        plwarn( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
         return;
     }
 
@@ -2203,12 +2203,12 @@ void plD_esc_xcairo( PLStream *pls, PLINT op, void *ptr )
         unsigned int         w, h, b, d;
         if ( xinfo == NULL )
         {
-            printf( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
+            plwarn( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
             return;
         }
         if ( aStream->xdrawable_mode == 0 )
         {
-            printf( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
+            plwarn( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
             return;
         }
         aStream->XDisplay = xinfo->display;
diff --git a/drivers/linuxvga.c b/drivers/linuxvga.c
index f59b347..d88d2a3 100644
--- a/drivers/linuxvga.c
+++ b/drivers/linuxvga.c
@@ -95,8 +95,7 @@ plD_init_vga( PLStream *pls )
         vga_setmode( mode );
     else
     {
-        printf( "Error: Video mode not supported by graphics card\n" );
-        exit( -1 );
+        plabort( "Error: Video mode not supported by graphics card\n" );
     }
 
 // If all is fine we get the dimensions and # of colors
diff --git a/drivers/pdf.c b/drivers/pdf.c
index 5f7dac8..dd32cd5 100644
--- a/drivers/pdf.c
+++ b/drivers/pdf.c
@@ -137,7 +137,7 @@ void
 error_handler( HPDF_STATUS error_no, HPDF_STATUS detail_no, void * PL_UNUSED( user_data ) )
 {
     // invoke longjmp() when an error has occurred
-    printf( "ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no );
+    plwarn( "ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no );
     longjmp( env, 1 );
 }
 
@@ -287,8 +287,7 @@ void plD_init_pdf( PLStream *pls )
         // can't call plexit because that appears to be circular via
         // what happens with plend.  Therefore, print out an error message
         // and exit.
-        fprintf( stderr, "ERROR in haru library\n" );
-        exit( 1 );
+        plexit( "ERROR in haru library\n" );
     }
 }
 
@@ -812,14 +811,14 @@ void process_string( PLStream* pls, EscText* args )
     // Check that we got unicode, warning message and return if not
     if ( args->unicode_array_len == 0 )
     {
-        printf( "Non unicode string passed to a pdf driver, ignoring\n" );
+        plwarn( "Non unicode string passed to a pdf driver, ignoring\n" );
         return;
     }
 
     // Check that unicode string isn't longer then the max we allow
     if ( args->unicode_array_len >= MAX_STRING_LEN )
     {
-        printf( "Sorry, the pdf drivers only handles strings of length < %d\n", MAX_STRING_LEN );
+        plwarn( "Sorry, the pdf drivers only handles strings of length < %d\n", MAX_STRING_LEN );
         return;
     }
 
diff --git a/drivers/plmeta.c b/drivers/plmeta.c
index 61a51c2..094d750 100644
--- a/drivers/plmeta.c
+++ b/drivers/plmeta.c
@@ -591,16 +591,12 @@ plm_text( PLStream *pls, EscText *args )
 static void
 handle_fsetpos_failed( const char *where, const char *which, FPOS_T position )
 {
-    char buffer[BUFFER_LEN];
-
     // Format a standard message detailing the failure location
-    snprintf( buffer, BUFFER_LEN,
+    plexit( 
         "%s: fsetpos to %s (%lu) failed",
         where,
         which,
         (unsigned long) position );
-
-    plexit( buffer );
 }
 
 //--------------------------------------------------------------------------
diff --git a/drivers/ps.c b/drivers/ps.c
index 8fd58d7..535e54e 100644
--- a/drivers/ps.c
+++ b/drivers/ps.c
@@ -63,8 +63,6 @@ static void  fill_polygon( PLStream *pls );
 static void  proc_str( PLStream *, EscText * );
 static void  esc_purge( unsigned char *, unsigned char * );
 
-#define OUTBUF_LEN    128
-static char   outbuf[OUTBUF_LEN];
 static int    text = 1;
 static int    color;
 static int    hrshsym = 1;
@@ -425,7 +423,7 @@ plD_line_ps( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
         else
             putc( ' ', OF );
 
-        snprintf( outbuf, OUTBUF_LEN, "%d %d D", x2, y2 );
+        pls->bytecnt += fprintf( OF, "%d %d D", x2, y2 );
         dev->ptcnt++;
         pls->linepos += 12;
     }
@@ -435,9 +433,9 @@ plD_line_ps( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
         pls->linepos = 0;
 
         if ( x1 == x2 && y1 == y2 ) // must be a single dot, draw a circle
-            snprintf( outbuf, OUTBUF_LEN, "%d %d A", x1, y1 );
+            pls->bytecnt += fprintf( OF, "%d %d A", x1, y1 );
         else
-            snprintf( outbuf, OUTBUF_LEN, "%d %d M %d %d D", x1, y1, x2, y2 );
+            pls->bytecnt += fprintf( OF, "%d %d M %d %d D", x1, y1, x2, y2 );
         dev->llx      = MIN( dev->llx, x1 );
         dev->lly      = MIN( dev->lly, y1 );
         dev->urx      = MAX( dev->urx, x1 );
@@ -450,8 +448,7 @@ plD_line_ps( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
     dev->urx = MAX( dev->urx, x2 );
     dev->ury = MAX( dev->ury, y2 );
 
-    fprintf( OF, "%s", outbuf );
-    pls->bytecnt += 1 + (PLINT) strlen( outbuf );
+    pls->bytecnt++;     // Add one for the putc() 
     dev->xold     = x2;
     dev->yold     = y2;
 }
@@ -682,13 +679,11 @@ fill_polygon( PLStream *pls )
 
         if ( n == 0 )
         {
-            snprintf( outbuf, OUTBUF_LEN, "N %d %d M", x, y );
+            pls->bytecnt += fprintf( OF, "N %d %d M", x, y );
             dev->llx = MIN( dev->llx, x );
             dev->lly = MIN( dev->lly, y );
             dev->urx = MAX( dev->urx, x );
             dev->ury = MAX( dev->ury, y );
-            fprintf( OF, "%s", outbuf );
-            pls->bytecnt += (PLINT) strlen( outbuf );
             continue;
         }
 
@@ -702,14 +697,12 @@ fill_polygon( PLStream *pls )
 
         pls->bytecnt++;
 
-        snprintf( outbuf, OUTBUF_LEN, "%d %d D", x, y );
+        pls->bytecnt += fprintf( OF, "%d %d D", x, y );
         dev->llx = MIN( dev->llx, x );
         dev->lly = MIN( dev->lly, y );
         dev->urx = MAX( dev->urx, x );
         dev->ury = MAX( dev->ury, y );
 
-        fprintf( OF, "%s", outbuf );
-        pls->bytecnt += (PLINT) strlen( outbuf );
         pls->linepos += 21;
     }
     dev->xold = PL_UNDEFINED;
diff --git a/drivers/wxwidgets_dev.cpp b/drivers/wxwidgets_dev.cpp
index 71621ff..4988f82 100644
--- a/drivers/wxwidgets_dev.cpp
+++ b/drivers/wxwidgets_dev.cpp
@@ -882,14 +882,14 @@ void wxPLDevice::ProcessString( PLStream* pls, EscText* args )
     // Check that we got unicode, warning message and return if not
     if ( args->unicode_array_len == 0 )
     {
-        printf( "Non unicode string passed to the wxWidgets driver, ignoring\n" );
+        plwarn( "Non unicode string passed to the wxWidgets driver, ignoring\n" );
         return;
     }
 
     // Check that unicode string isn't longer then the max we allow
     if ( args->unicode_array_len >= 500 )
     {
-        printf( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
+        plwarn( "Sorry, the wxWidgets drivers only handles strings of length < %d\n", 500 );
         return;
     }
 
diff --git a/drivers/xwin.c b/drivers/xwin.c
index 982d28f..f1790a8 100644
--- a/drivers/xwin.c
+++ b/drivers/xwin.c
@@ -628,7 +628,7 @@ plD_state_xw( PLStream *pls, PLINT op )
                 PLColor_to_XColor( &pls->curcolor, &dev->curcolor );
                 if ( !XAllocColor( xwd->display, xwd->map, &dev->curcolor ) )
                 {
-                    fprintf( stderr, "Warning: could not allocate color\n" );
+                    plwarn( "Warning: could not allocate color\n" );
                     dev->curcolor.pixel = xwd->fgcolor.pixel;
                 }
             }
@@ -2425,7 +2425,7 @@ static void ConfigBufferingCmd( PLStream *pls, PLBufferingCB *ptr )
         break;
 
     default:
-        printf( "Unrecognized buffering request ignored.\n" );
+        plwarn( "Unrecognized buffering request ignored.\n" );
         break;
     }
 }
@@ -2501,7 +2501,7 @@ CreatePixmapErrorHandler( Display *display, XErrorEvent *error )
     {
         char buffer[256];
         XGetErrorText( display, error->error_code, buffer, 256 );
-        fprintf( stderr, "Error in XCreatePixmap: %s.\n", buffer );
+        plwarn( "Error in XCreatePixmap: %s.\n", buffer );
     }
     return 1;
 }
@@ -2536,7 +2536,7 @@ CreatePixmap( PLStream *pls )
         dev->write_to_pixmap = 0;
         dev->write_to_window = 1;
         pls->db = 0;
-        fprintf( stderr, "\n\
+        plwarn( "\n\
 Warning: pixmap could not be allocated (insufficient memory on server).\n\
 Driver will redraw the entire plot to handle expose events.\n" );
     }
@@ -2723,7 +2723,7 @@ AllocBGFG( PLStream *pls )
         xwd->cmap0[0].pixel = BlackPixel( xwd->display, xwd->screen );
         xwd->fgcolor.pixel  = WhitePixel( xwd->display, xwd->screen );
         if ( xwd->rw_cmap && pls->verbose )
-            fprintf( stderr, "Downgrading to r/o cmap.\n" );
+            plwarn( "Downgrading to r/o cmap.\n" );
         xwd->rw_cmap = 0;
         return;
     }
@@ -3062,7 +3062,7 @@ AllocCmap0( PLStream *pls )
                 XColor screen_def, exact_def;
 
                 if ( pls->verbose )
-                    fprintf( stderr,
+                    plwarn( 
                         "color alloc failed, trying by name: %s.\n",
                         pls->cmap0[i].name );
 
@@ -3092,7 +3092,7 @@ AllocCmap0( PLStream *pls )
                         xwd->cmap0[i].pixel = screen_def.pixel;
                     }
                     else
-                        printf( "Can't find white?! Giving up...\n" );
+                        plwarn( "Can't find white?! Giving up...\n" );
                 }
             }
         }
@@ -3142,7 +3142,7 @@ AllocCmap1( PLStream *pls )
         if ( npixels < 2 )
         {
             xwd->ncol1 = -1;
-            fprintf( stderr, "Warning: unable to allocate sufficient colors in cmap1.\n" );
+            plwarn( "Warning: unable to allocate sufficient colors in cmap1.\n" );
             return;
         }
 
@@ -3220,7 +3220,7 @@ AllocCmap1( PLStream *pls )
         if ( i < ncolors )
         {
             xwd->ncol1 = -1;
-            fprintf( stderr,
+            plwarn( 
                 "Warning: unable to allocate sufficient colors in cmap1\n" );
             return;
         }
@@ -3415,7 +3415,7 @@ GetImageErrorHandler( Display *display, XErrorEvent *error )
     {
         char buffer[256];
         XGetErrorText( display, error->error_code, buffer, 256 );
-        fprintf( stderr, "xwin: Error in XGetImage: %s.\n", buffer );
+        plwarn( "xwin: Error in XGetImage: %s.\n", buffer );
     }
     return 1;
 }
diff --git a/include/plplotP.h b/include/plplotP.h
index bc4f3c4..c010b84 100644
--- a/include/plplotP.h
+++ b/include/plplotP.h
@@ -552,7 +552,7 @@ plfill_soft( short *x, short *y, PLINT npts );
 // error message and tries to clean up as much as possible.
 
 PLDLLIMPEXP void
-plexit( const char *errormsg );
+plexit( const char *errormsg, ... );
 
 // Just a front-end to exit().
 
@@ -562,12 +562,12 @@ pl_exit( void );
 // A handy way to issue warnings, if need be.
 
 PLDLLIMPEXP void
-plwarn( const char *errormsg );
+plwarn( const char *errormsg, ... );
 
 // Same as plwarn(), but appends ", aborting plot" to the error message
 
 PLDLLIMPEXP void
-plabort( const char *errormsg );
+plabort( const char *errormsg, ... );
 
 // Loads either the standard or extended font.
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b4f9683..7eb56af 100755
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,6 +31,7 @@ set(plplot_LIB_SRCS
   plctrl.c
   plcvt.c
   pldtik.c
+  plerror.c
   plf2ops.c
   plfill.c
   plfreetype.c
diff --git a/src/pdfutils.c b/src/pdfutils.c
index 1fc0af0..c45be3a 100644
--- a/src/pdfutils.c
+++ b/src/pdfutils.c
@@ -955,7 +955,7 @@ pdf_wr_ieeef( PDFstrm *pdfs, float f )
     if ( e_ieee > 255 )
     {
         if ( debug )
-            fprintf( stderr, "pdf_wr_ieeef: Warning -- overflow\n" );
+            pldebug( "pdf_wr_ieeef", "Warning -- overflow\n" );
         e_ieee = 255;
     }
 
@@ -969,7 +969,7 @@ pdf_wr_ieeef( PDFstrm *pdfs, float f )
 
     if ( debug )
     {
-        fprintf( stderr, "Float value (written):      %g\n", fsgl );
+        pldebug( "pdf_wr_ieeef", "Float value (written):      %g\n", fsgl );
         print_ieeef( &fsgl, &value );
     }
 
@@ -1024,7 +1024,7 @@ pdf_rd_ieeef( PDFstrm *pdfs, float *pf )
 
     if ( debug )
     {
-        fprintf( stderr, "Float value (read):      %g\n", fsgl );
+        pldebug( "pl_rd_ieeef", "Float value (read):      %g\n", fsgl );
         print_ieeef( &fsgl, &value );
     }
 
diff --git a/src/plargs.c b/src/plargs.c
index be8527f..08050ce 100644
--- a/src/plargs.c
+++ b/src/plargs.c
@@ -775,7 +775,7 @@ c_plsetopt( const char * opt, const char *opt_arg )
     status = plparseopts( &argc, argv, mode );
     if ( status )
     {
-        fprintf( stderr, "plSetOpt: Unrecognized option %s\n", opt );
+        plwarn( "plSetOpt: Unrecognized option %s", opt );
     }
     return status;
 }
@@ -977,7 +977,7 @@ c_plparseopts( int *p_argc, const char **argv, PLINT mode )
             }
             if ( !mode_quiet && mode_full )
             {
-                fprintf( stderr, "\nBad command line option \"%s\"\n", argv[0] );
+                plwarn( "Bad command line option \"%s\"", argv[0] );
                 plOptUsage();
             }
             if ( mode_full )
@@ -991,7 +991,7 @@ c_plparseopts( int *p_argc, const char **argv, PLINT mode )
 
             if ( !mode_quiet )
             {
-                fprintf( stderr, "\nBad command line option \"%s\"\n", argv[0] );
+                plwarn( "Bad command line option \"%s\"", argv[0] );
                 plOptUsage();
             }
             if ( mode_full )
@@ -1135,8 +1135,8 @@ ProcessOpt( const char * opt, PLOptionTable *tab, int *p_myargc, const char ***p
 
         if ( tab->handler == NULL )
         {
-            fprintf( stderr,
-                "ProcessOpt: no handler specified for option %s\n",
+            plwarn( 
+                "ProcessOpt: no handler specified for option %s",
                 tab->opt );
             return 1;
         }
@@ -1167,8 +1167,8 @@ ProcessOpt( const char * opt, PLOptionTable *tab, int *p_myargc, const char ***p
 
         if ( tab->var == NULL )
         {
-            fprintf( stderr,
-                "ProcessOpt: no variable specified for option %s\n",
+            plwarn(
+                "ProcessOpt: no variable specified for option %s",
                 tab->opt );
             return 1;
         }
@@ -1181,8 +1181,8 @@ ProcessOpt( const char * opt, PLOptionTable *tab, int *p_myargc, const char ***p
 
         if ( tab->var == NULL )
         {
-            fprintf( stderr,
-                "ProcessOpt: no variable specified for option %s\n",
+            plwarn( 
+                "ProcessOpt: no variable specified for option %s",
                 tab->opt );
             return 1;
         }
@@ -1195,8 +1195,8 @@ ProcessOpt( const char * opt, PLOptionTable *tab, int *p_myargc, const char ***p
 
         if ( tab->var == NULL )
         {
-            fprintf( stderr,
-                "ProcessOpt: no variable specified for option %s\n",
+            plwarn(
+                "ProcessOpt: no variable specified for option %s",
                 tab->opt );
             return 1;
         }
@@ -1214,8 +1214,8 @@ ProcessOpt( const char * opt, PLOptionTable *tab, int *p_myargc, const char ***p
 
         // Somebody messed up..
 
-        fprintf( stderr,
-            "ProcessOpt: invalid processing mode for option %s\n",
+        plwarn(
+            "ProcessOpt: invalid processing mode for option %s",
             tab->opt );
         return 1;
     }
@@ -1266,7 +1266,7 @@ GetOptarg( const char **popt_arg, int *p_myargc, const char ***p_argv, int *p_ar
     {
         if ( !mode_quiet )
         {
-            fprintf( stderr, "Argument missing for %s option.\n", ( *p_argv )[0] );
+            plwarn( "Argument missing for %s option.", ( *p_argv )[0] );
             plOptUsage();
         }
     }
@@ -1463,8 +1463,6 @@ plParseDrvOpts( DrvOpt *acc_opt )
     DrvOptCmd *drvp;
     DrvOpt    *t;
     int       fl;
-    char      msg[80];
-    memset( msg, '\0', sizeof ( msg ) );
 
     if ( !drv_opt.option )
         return 1;
@@ -1490,8 +1488,8 @@ plParseDrvOpts( DrvOpt *acc_opt )
                 case DRV_INT:
                     if ( sscanf( drvp->value, "%d", (int *) t->var_ptr ) != 1 )
                     {
-                        snprintf( msg, sizeof ( msg ) - 1, "Incorrect argument to '%s' option", drvp->option );
-                        plexit( msg );
+                        plexit( "Incorrect argument to '%s' option", 
+                                drvp->option );
                     }
 #ifdef DEBUG
                     fprintf( stderr, "plParseDrvOpts: %s %d\n", t->opt, *(int *) t->var_ptr );
@@ -1501,8 +1499,8 @@ plParseDrvOpts( DrvOpt *acc_opt )
                 case DRV_FLT:
                     if ( sscanf( drvp->value, "%f", (float *) t->var_ptr ) != 1 )
                     {
-                        snprintf( msg, sizeof ( msg ) - 1, "Incorrect argument to '%s' option", drvp->option );
-                        plexit( msg );
+                        plexit( "Incorrect argument to '%s' option", 
+                                drvp->option );
                     }
 #ifdef DEBUG
                     fprintf( stderr, "plParseDrvOpts: %s %f\n", t->opt, *(float *) t->var_ptr );
@@ -1515,8 +1513,7 @@ plParseDrvOpts( DrvOpt *acc_opt )
 
         if ( !fl )
         {
-            snprintf( msg, sizeof ( msg ) - 1, "Option '%s' not recognized.\n\nRecognized options for this driver are:\n", drvp->option );
-            plwarn( msg );
+            plwarn( "Option '%s' not recognized.\n\nRecognized options for this driver are:\n", drvp->option );
             plHelpDrvOpts( acc_opt );
             plexit( "" );
         }
@@ -1921,7 +1918,7 @@ opt_width( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED(
     width = atof( opt_arg );
     if ( width < 0. )
     {
-        fprintf( stderr, "?invalid width\n" );
+        plwarn( "?invalid width\n" );
         return 1;
     }
     else
@@ -2005,7 +2002,7 @@ opt_bg( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED( cl
         break;
 
     default:
-        fprintf( stderr, "Unrecognized background color value %s\n", color_field );
+        plwarn( "Unrecognized background color value %s", color_field );
         return 1;
     }
 
@@ -2277,7 +2274,7 @@ opt_fsiz( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED(
     bytemax = (PLINT) ( multiplier * atof( spec ) );
     if ( bytemax <= 0 )
     {
-        fprintf( stderr, "?invalid file size %d. 2.14G is the maximum.\n", bytemax );
+        plwarn( "?invalid file size %d. 2.14G is the maximum.", bytemax );
         return 1;
     }
     plsfam( 1, -1, bytemax );
@@ -2606,40 +2603,40 @@ opt_geo( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED( c
         xoff = 0;
         yoff = 0;
         if ( xwid == 0 )
-            fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid xwid in -geometry %s\n", opt_arg );
         if ( ywid == 0 )
-            fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid ywid in -geometry %s\n", opt_arg );
         if ( xwid < 0 )
         {
-            fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid xwid in -geometry %s\n", opt_arg );
             return 1;
         }
         if ( ywid < 0 )
         {
-            fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid ywid in -geometry %s\n", opt_arg );
             return 1;
         }
     }
     else if ( numargs == 4 )
     {
         if ( xwid == 0 )
-            fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid xwid in -geometry %s\n", opt_arg );
         if ( ywid == 0 )
-            fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid ywid in -geometry %s\n", opt_arg );
         if ( xwid < 0 )
         {
-            fprintf( stderr, "?invalid xwid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid xwid in -geometry %s\n", opt_arg );
             return 1;
         }
         if ( ywid < 0 )
         {
-            fprintf( stderr, "?invalid ywid in -geometry %s\n", opt_arg );
+            plwarn( "?invalid ywid in -geometry %s\n", opt_arg );
             return 1;
         }
         if ( abs( xoff ) == 0 )
-            fprintf( stderr, "?invalid xoff in -geometry %s\n", opt_arg );
+            plwarn( "?invalid xoff in -geometry %s\n", opt_arg );
         if ( abs( yoff ) == 0 )
-            fprintf( stderr, "?invalid yoff in -geometry %s\n", opt_arg );
+            plwarn( "?invalid yoff in -geometry %s\n", opt_arg );
     }
     else
     {
@@ -2649,13 +2646,13 @@ opt_geo( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED( c
             xwid = 0;
             ywid = 0;
             if ( abs( xoff ) == 0 )
-                fprintf( stderr, "?invalid xoff in -geometry %s\n", opt_arg );
+                plwarn( "?invalid xoff in -geometry %s\n", opt_arg );
             if ( abs( yoff ) == 0 )
-                fprintf( stderr, "?invalid yoff in -geometry %s\n", opt_arg );
+                plwarn( "?invalid yoff in -geometry %s\n", opt_arg );
         }
         else
         {
-            fprintf( stderr, "?invalid -geometry %s\n", opt_arg );
+            plwarn( "?invalid -geometry %s\n", opt_arg );
             return 1;
         }
     }
@@ -2721,14 +2718,14 @@ opt_dpi( const char * PL_UNUSED( opt ), const char *opt_arg, void * PL_UNUSED( c
         field = strtok( opttmp, "x" );
         xdpi  = atof( field );
         if ( xdpi == 0 )
-            fprintf( stderr, "?invalid xdpi\n" );
+            plwarn( "?invalid xdpi\n" );
 
         if ( ( field = strtok( NULL, " " ) ) == NULL )
             return 1;
 
         ydpi = atof( field );
         if ( ydpi == 0 )
-            fprintf( stderr, "?invalid ydpi\n" );
+            plwarn( "?invalid ydpi\n" );
     }
     else
     {
@@ -2763,7 +2760,7 @@ opt_dev_compression( const char * PL_UNUSED( opt ), const char *opt_arg, void *
     comp = atoi( opt_arg );
     if ( comp == 0 )
     {
-        fprintf( stderr, "?invalid compression\n" );
+        plwarn( "?invalid compression\n" );
         return 1;
     }
     plscompression( comp );
diff --git a/src/plbuf.c b/src/plbuf.c
index b72782e..2c9ec7c 100644
--- a/src/plbuf.c
+++ b/src/plbuf.c
@@ -760,11 +760,9 @@ rdbuf_state( PLStream *pls )
         {
             if ( pls->icol0 >= pls->ncol0 )
             {
-                char buffer[256];
-                snprintf( buffer, 256,
+                plabort(
                     "rdbuf_state: Invalid color map entry: %d",
                     pls->icol0 );
-                plabort( buffer );
                 return;
             }
             r = pls->cmap0[pls->icol0].r;
@@ -1437,7 +1435,7 @@ check_buffer_size( PLStream *pls, size_t data_size )
                                     + 1 );
 
         if ( pls->verbose )
-            printf( "Growing buffer to %d KB\n",
+            pldebug( "Growing buffer to %d KB\n",
                 (int) ( pls->plbuf_buffer_size / 1024 ) );
 
         if ( ( pls->plbuf_buffer
diff --git a/src/plcore.c b/src/plcore.c
index 2378a94..9f3807c 100644
--- a/src/plcore.c
+++ b/src/plcore.c
@@ -538,14 +538,12 @@ plP_gradient( short *x, short *y, PLINT npts )
 int text2num( const char *text, char end, PLUNICODE *num )
 {
     char *endptr;
-    char msgbuf[BUFFER_SIZE];
 
     *num = (PLUNICODE) strtoul( text, &endptr, 0 );
 
     if ( end != endptr[0] )
     {
-        snprintf( msgbuf, BUFFER_SIZE, "text2num: invalid control string detected - %c expected", end );
-        plwarn( msgbuf );
+        plwarn( "text2num: invalid control string detected - %c expected", end );
     }
 
     return (int) ( endptr - text );
@@ -849,13 +847,9 @@ void alternate_unicode_processing( const char * string, EscText * args )
 #endif
             if ( ptr == NULL )
             {
-                char buf[BUFFER_SIZE];
-                char tmpstring[31];
-                strncpy( tmpstring, string, 30 );
-                tmpstring[30] = '\0';
-                snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
-                    tmpstring, strlen( string ) > 30 ? "[...]" : "" );
-                plabort( buf );
+                // Limit the offending string length to 30 characters
+                plabort( "UTF-8 string is malformed: %.30s%s",
+                    string, strlen( string ) > 30 ? "[...]" : "" );
                 return;
             }
             i += (int) ( ptr - ( string + i ) - 1 );
@@ -1101,13 +1095,9 @@ void encode_unicode( const char * string, EscText *args )
 #endif
             if ( ptr == NULL )
             {
-                char buf[BUFFER_SIZE];
-                char tmpstring[31];
-                strncpy( tmpstring, string, 30 );
-                tmpstring[30] = '\0';
-                snprintf( buf, BUFFER_SIZE, "UTF-8 string is malformed: %s%s",
-                    tmpstring, strlen( string ) > 30 ? "[...]" : "" );
-                plabort( buf );
+                // Limit the offending string to 30 characters
+                plabort( "UTF-8 string is malformed: %.30s%s",
+                    string, strlen( string ) > 30 ? "[...]" : "" );
                 return;
             }
             args->unicode_array[j] = unichar;
@@ -2575,7 +2565,7 @@ c_plsstrm( PLINT strm )
 {
     if ( strm < 0 || strm >= PL_NSTREAMS )
     {
-        fprintf( stderr,
+        plwarn( 
             "plsstrm: Illegal stream number %d, must be in [0, %d]\n",
             (int) strm, PL_NSTREAMS );
     }
@@ -2633,7 +2623,7 @@ c_plmkstrm( PLINT *p_strm )
 
     if ( i == PL_NSTREAMS )
     {
-        fprintf( stderr, "plmkstrm: Cannot create new stream\n" );
+        plwarn( "plmkstrm: Cannot create new stream\n" );
         *p_strm = -1;
     }
     else
@@ -2719,7 +2709,7 @@ c_plcpstrm( PLINT iplsr, PLINT flags )
     plsr = pls[iplsr];
     if ( plsr == NULL )
     {
-        fprintf( stderr, "plcpstrm: stream %d not in use\n", (int) iplsr );
+        plwarn( "plcpstrm: stream %d not in use\n", (int) iplsr );
         return;
     }
 
@@ -3035,10 +3025,9 @@ plInitDispatchTable()
             {
                 closedir( dp_drvdir );
                 fclose( fp_drvdb );
-                snprintf( buf, BUFFER2_SIZE,
+                plabort( 
                     "plInitDispatchTable: Could not open driver info file %s\n",
                     name );
-                plabort( buf );
                 return;
             }
 
@@ -3255,7 +3244,7 @@ plSelectDev()
         }
         else
         {
-            fprintf( stderr, "Requested device %s not available\n",
+            plwarn( "Requested device %s not available\n",
                 plsc->DevName );
         }
     }
@@ -3356,8 +3345,9 @@ plLoadDriver( void )
 //
     if ( i == npldynamicdevices )
     {
-        fprintf( stderr, "No such device: %s.\n", dev->pl_DevName );
-        plexit( "plLoadDriver detected device logic screwup" );
+        plexit( "No such device: %s.\n%s", 
+                dev->pl_DevName,
+                "plLoadDriver detected device logic screwup" );
     }
 
 // Note the device tag, and the driver index. Note that a given driver could
@@ -3406,8 +3396,7 @@ plLoadDriver( void )
     {
         pldebug( "plLoadDriver", "lt_dlopenext failed because of "
             "the following reason:\n%s\n", lt_dlerror() );
-        fprintf( stderr, "Unable to load driver: %s.\n", driver->drvnam );
-        plexit( "Unable to load driver" );
+        plexit( "Unable to load driver: %s.\n", driver->drvnam );
     }
 
 // Now we are ready to ask the driver's device dispatch init function to
@@ -3418,7 +3407,7 @@ plLoadDriver( void )
         PLDispatchInit dispatch_init = (PLDispatchInit) lt_dlsym( driver->dlhand, sym );
         if ( !dispatch_init )
         {
-            fprintf( stderr,
+            plwarn(
                 "Unable to locate dispatch table initialization function for driver: %s.\n",
                 driver->drvnam );
             return;
diff --git a/src/plctrl.c b/src/plctrl.c
index 35595c7..566352c 100644
--- a/src/plctrl.c
+++ b/src/plctrl.c
@@ -62,7 +62,6 @@
 #define BUFFER_SIZE    256
 #define COLLEN         30
 #define PALLEN         160
-#define MSGLEN         1024
 
 // small epsilon for fuzzy range checks that is still large enough to
 // work even in the single precision floating point case.
@@ -79,12 +78,6 @@ color_set( PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, PLFLT a, const char *name );
 static void
 strcat_delim( char *dirspec );
 
-static int
-( *exit_handler )( const char *errormsg );
-
-static void
-( *abort_handler )( const char *errormsg );
-
 static void
 plcmap0_def( int imin, int imax );
 
@@ -147,9 +140,7 @@ c_plcol0( PLINT icol0 )
     }
     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plcol0: Invalid color map entry: %d", (int) icol0 );
-        plabort( buffer );
+        plabort( "plcol0: Invalid color map entry: %d", (int) icol0 );
         return;
     }
 
@@ -183,9 +174,7 @@ c_plcol1( PLFLT col1 )
     }
     if ( col1 < 0 || col1 > 1 || isnan( col1 ) )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plcol1: Invalid color map position: %f", (PLFLT) col1 );
-        plabort( buffer );
+        plabort( "plcol1: Invalid color map position: %f", (PLFLT) col1 );
         return;
     }
 
@@ -285,17 +274,13 @@ c_plscol0( PLINT icol0, PLINT r, PLINT g, PLINT b )
         plscmap0n( 0 );
     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plscol0: Illegal color table value: %d", (int) icol0 );
-        plabort( buffer );
+        plabort( "plscol0: Illegal color table value: %d", (int) icol0 );
         return;
     }
     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plscol0: Invalid RGB color: %d, %d, %d",
+        plabort( "plscol0: Invalid RGB color: %d, %d, %d",
             (int) r, (int) g, (int) b );
-        plabort( buffer );
         return;
     }
 
@@ -321,17 +306,13 @@ c_plscol0a( PLINT icol0, PLINT r, PLINT g, PLINT b, PLFLT alpha )
         plscmap0n( 0 );
     if ( icol0 < 0 || icol0 >= plsc->ncol0 )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plscol0a: Illegal color table value: %d", (int) icol0 );
-        plabort( buffer );
+        plabort( "plscol0a: Illegal color table value: %d", (int) icol0 );
         return;
     }
     if ( ( r < 0 || r > 255 ) || ( g < 0 || g > 255 ) || ( b < 0 || b > 255 ) || ( alpha < 0. || alpha > 1.0 ) )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plscol0a: Invalid RGB color: %d, %d, %d, %f",
+        plabort( "plscol0a: Invalid RGB color: %d, %d, %d, %f",
             (int) r, (int) g, (int) b, (double) alpha );
-        plabort( buffer );
         return;
     }
 
@@ -367,9 +348,7 @@ c_plgcol0( PLINT icol0, PLINT *r, PLINT *g, PLINT *b )
 
     if ( icol0 < 0 || icol0 > plsc->ncol0 )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
-        plabort( buffer );
+        plabort( "plgcol0: Invalid color index: %d", (int) icol0 );
         return;
     }
 
@@ -405,9 +384,7 @@ c_plgcol0a( PLINT icol0, PLINT *r, PLINT *g, PLINT *b, PLFLT *alpha )
 
     if ( icol0 < 0 || icol0 > plsc->ncol0 )
     {
-        char buffer[BUFFER_SIZE];
-        snprintf( buffer, BUFFER_SIZE, "plgcol0: Invalid color index: %d", (int) icol0 );
-        plabort( buffer );
+        plabort( "plgcol0: Invalid color index: %d", (int) icol0 );
         return;
     }
 
@@ -443,10 +420,8 @@ c_plscmap0( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol0 )
              ( g[i] < 0 || g[i] > 255 ) ||
              ( b[i] < 0 || b[i] > 255 ) )
         {
-            char buffer[BUFFER_SIZE];
-            snprintf( buffer, BUFFER_SIZE, "plscmap0: Invalid RGB color: %d, %d, %d",
+            plabort( "plscmap0: Invalid RGB color: %d, %d, %d",
                 (int) r[i], (int) g[i], (int) b[i] );
-            plabort( buffer );
             return;
         }
 
@@ -486,10 +461,8 @@ c_plscmap0a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *alpha,
              ( b[i] < 0 || b[i] > 255 ) ||
              ( alpha[i] < 0.0 || alpha[i] > 1.0 ) )
         {
-            char buffer[BUFFER_SIZE];
-            snprintf( buffer, BUFFER_SIZE, "plscmap0a: Invalid RGB color: %d, %d, %d, %f",
+            plabort( "plscmap0a: Invalid RGB color: %d, %d, %d, %f",
                 (int) r[i], (int) g[i], (int) b[i], (double) alpha[i] );
-            plabort( buffer );
             return;
         }
 
@@ -527,10 +500,8 @@ c_plscmap1( const PLINT *r, const PLINT *g, const PLINT *b, PLINT ncol1 )
              ( g[i] < 0 || g[i] > 255 ) ||
              ( b[i] < 0 || b[i] > 255 ) )
         {
-            char buffer[BUFFER_SIZE];
-            snprintf( buffer, BUFFER_SIZE, "plscmap1: Invalid RGB color: %d, %d, %d",
+            plabort( "plscmap1: Invalid RGB color: %d, %d, %d",
                 (int) r[i], (int) g[i], (int) b[i] );
-            plabort( buffer );
             return;
         }
         plsc->cmap1[i].r = (unsigned char) r[i];
@@ -569,10 +540,8 @@ c_plscmap1a( const PLINT *r, const PLINT *g, const PLINT *b, const PLFLT *alpha,
              ( b[i] < 0 || b[i] > 255 ) ||
              ( alpha[i] < 0.0 || alpha[i] > 1.0 ) )
         {
-            char buffer[BUFFER_SIZE];
-            snprintf( buffer, BUFFER_SIZE, "plscmap1a: Invalid RGB color: %d, %d, %d, %f",
+            plabort( "plscmap1a: Invalid RGB color: %d, %d, %d, %f",
                 (int) r[i], (int) g[i], (int) b[i], (double) alpha[i] );
-            plabort( buffer );
             return;
         }
         plsc->cmap1[i].r = (unsigned char) r[i];
@@ -1397,11 +1366,14 @@ read_line( char *buffer, int length, FILE *fp )
 
 void
 cmap0_palette_read( const char *filename,
-                    int *number_colors, unsigned int **r, unsigned int **g, unsigned int **b, double **a )
+                    int *number_colors, 
+                    unsigned int **r, 
+                    unsigned int **g, 
+                    unsigned int **b, 
+                    double **a )
 {
     int  i, err = 0;
     char color_info[COLLEN];
-    char msgbuf[MSGLEN];
     FILE *fp;
     char * save_locale = plsave_set_locale();
 
@@ -1410,8 +1382,7 @@ cmap0_palette_read( const char *filename,
         fp = plLibOpen( PL_DEFAULT_CMAP0_FILE );
         if ( fp == NULL )
         {
-            snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
-            plwarn( msgbuf );
+            plwarn( "Unable to open cmap0 file %s\n", PL_DEFAULT_CMAP0_FILE );
             err = 1;
         }
     }
@@ -1420,16 +1391,14 @@ cmap0_palette_read( const char *filename,
         fp = plLibOpen( filename );
         if ( fp == NULL )
         {
-            snprintf( msgbuf, MSGLEN, "Unable to open cmap0 file %s\n", filename );
-            plwarn( msgbuf );
+            plwarn( "Unable to open cmap0 file %s\n", filename );
             err = 1;
         }
     }
     if ( !err && ( fscanf( fp, "%d\n", number_colors ) != 1 || *number_colors < 1 ) )
     {
         fclose( fp );
-        snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 header\n" );
-        plwarn( msgbuf );
+        plwarn( "Unrecognized cmap0 header\n" );
         err = 1;
     }
 
@@ -1499,9 +1468,8 @@ cmap0_palette_read( const char *filename,
         fclose( fp );
         if ( err )
         {
-            snprintf( msgbuf, MSGLEN, "Unrecognized cmap0 format data line.  Line is %s\n",
+            plwarn( "Unrecognized cmap0 format data line.  Line is %s\n",
                 color_info );
-            plwarn( msgbuf );
             free( *r );
             free( *g );
             free( *b );
@@ -1581,8 +1549,7 @@ c_plspal0( const char *filename )
 //! @param err_number The error number.
 #define fuzzy_range_check( value, min, max, fuzz, err_number )                                                                        \
     if ( value < ( min - fuzz ) || value > ( max + fuzz ) ) {                                                                         \
-        snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format data line.  Error number is %d. Line is %s\n", err_number, color_info ); \
-        plwarn( msgbuf );                                                                                                             \
+        plwarn( "Unrecognized cmap1 format data line.  Error number is %d. Line is %s\n", err_number, color_info ); \
         err = 1;                                                                                                                      \
         break;                                                                                                                        \
     } else if ( value < min ) {                                                                                                       \
@@ -1615,7 +1582,6 @@ c_plspal1( const char *filename, PLBOOL interpolate )
     PLINT        *ri, *gi, *bi;
     PLBOOL       *alt_hue_path;
     FILE         *fp;
-    char         msgbuf[MSGLEN];
     char         * save_locale = plsave_set_locale();
 
     rgb            = TRUE;
@@ -1626,8 +1592,7 @@ c_plspal1( const char *filename, PLBOOL interpolate )
         fp = plLibOpen( PL_DEFAULT_CMAP1_FILE );
         if ( fp == NULL )
         {
-            snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
-            plwarn( msgbuf );
+            plwarn( "Unable to open cmap1 .pal file %s\n", PL_DEFAULT_CMAP1_FILE );
             goto finish;
         }
     }
@@ -1636,16 +1601,14 @@ c_plspal1( const char *filename, PLBOOL interpolate )
         fp = plLibOpen( filename );
         if ( fp == NULL )
         {
-            snprintf( msgbuf, MSGLEN, "Unable to open cmap1 .pal file %s\n", filename );
-            plwarn( msgbuf );
+            plwarn( "Unable to open cmap1 .pal file %s\n", filename );
             goto finish;
         }
     }
     // Check for new file format
     if ( read_line( color_info, PALLEN, fp ) == NULL )
     {
-        snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
-        plwarn( msgbuf );
+        plwarn( "Error reading cmap1 .pal file %s\n", filename );
         fclose( fp );
         goto finish;
     }
@@ -1658,14 +1621,12 @@ c_plspal1( const char *filename, PLBOOL interpolate )
             rgb = TRUE;
         else
         {
-            snprintf( msgbuf, MSGLEN, "Invalid color space %s - assuming RGB\n", &color_info[3] );
-            plwarn( msgbuf );
+            plwarn( "Invalid color space %s - assuming RGB\n", &color_info[3] );
             rgb = TRUE;
         }
         if ( read_line( color_info, PALLEN, fp ) == NULL )
         {
-            snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
-            plwarn( msgbuf );
+            plwarn( "Error reading cmap1 .pal file %s\n", filename );
             fclose( fp );
             goto finish;
         }
@@ -1673,8 +1634,7 @@ c_plspal1( const char *filename, PLBOOL interpolate )
 
     if ( sscanf( color_info, "%d\n", &number_colors ) != 1 || number_colors < 2 )
     {
-        snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
-        plwarn( msgbuf );
+        plwarn( "Unrecognized cmap1 format (wrong number of colors) %s\n", color_info );
         fclose( fp );
         goto finish;
     }
@@ -1697,8 +1657,7 @@ c_plspal1( const char *filename, PLBOOL interpolate )
         {
             if ( read_line( color_info, PALLEN, fp ) == NULL )
             {
-                snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
-                plwarn( msgbuf );
+                plwarn( "Error reading cmap1 .pal file %s\n", filename );
                 fclose( fp );
                 goto finish;
             }
@@ -1707,8 +1666,7 @@ c_plspal1( const char *filename, PLBOOL interpolate )
             return_sscanf          = sscanf( color_info, "#%2x%2x%2x %d %d", &r_i, &g_i, &b_i, &pos_i, &alt_hue_path_i );
             if ( return_sscanf < 4 || ( return_sscanf_old != 0 && return_sscanf != return_sscanf_old ) )
             {
-                snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
-                plwarn( msgbuf );
+                plwarn( "Unrecognized cmap1 format (wrong number of items for version 1 of format) %s\n", color_info );
                 err = 1;
                 break;
             }
@@ -1744,15 +1702,13 @@ c_plspal1( const char *filename, PLBOOL interpolate )
         {
             if ( read_line( color_info, PALLEN, fp ) == NULL )
             {
-                snprintf( msgbuf, MSGLEN, "Error reading cmap1 .pal file %s\n", filename );
-                plwarn( msgbuf );
+                plwarn( "Error reading cmap1 .pal file %s\n", filename );
                 fclose( fp );
                 goto finish;
             }
             if ( sscanf( color_info, "%lf %lf %lf %lf %lf %d", &pos_d, &r_d, &g_d, &b_d, &a_d, &alt_hue_path_i ) != 6 )
             {
-                snprintf( msgbuf, MSGLEN, "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
-                plwarn( msgbuf );
+                plwarn( "Unrecognized cmap1 format (wrong number of items for version 2 of format) %s\n", color_info );
                 err = 1;
                 break;
             }
@@ -1843,143 +1799,6 @@ finish: plrestore_locale( save_locale );
 //--------------------------------------------------------------------------
 
 //--------------------------------------------------------------------------
-// void plwarn()
-//
-//! A handy way to issue warnings, if need be.
-//!
-//! @param errormsg The error message.
-
-void
-plwarn( const char *errormsg )
-{
-    int was_gfx = 0;
-
-    if ( plsc->graphx == 1 )
-    {
-        was_gfx = 1;
-        pltext();
-    }
-
-    fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
-    if ( *errormsg != '\0' )
-        fprintf( stderr, "%s\n", errormsg );
-
-    if ( was_gfx == 1 )
-        plgra();
-}
-
-//--------------------------------------------------------------------------
-// void plabort()
-//
-//! Much the same as plwarn(), but appends ", aborting operation" to the
-//! error message.  Helps to keep source code uncluttered and provides a
-//! convention for error aborts.
-//!
-//! If cleanup needs to be done in the main program, the user should write
-//! his/her own exit handler and pass it in via plsabort().
-//!
-//! @param errormsg The error message.
-
-void
-plabort( const char *errormsg )
-{
-    if ( abort_handler != NULL )
-        ( *abort_handler )( errormsg );
-
-    if ( plsc->errcode != NULL )
-        *( plsc->errcode ) = 1;
-
-    if ( plsc->errmsg != NULL )
-    {
-        sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
-        if ( *errormsg != '\0' )
-            sprintf( plsc->errmsg, "%s, aborting operation\n", errormsg );
-    }
-    else
-    {
-        int was_gfx = 0;
-
-        if ( plsc->graphx == 1 )
-        {
-            was_gfx = 1;
-            pltext();
-        }
-
-        fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
-        if ( *errormsg != '\0' )
-            fprintf( stderr, "%s, aborting operation\n", errormsg );
-
-        if ( was_gfx == 1 )
-            plgra();
-    }
-}
-
-
-//--------------------------------------------------------------------------
-// void plsabort()
-//
-//! Sets an optional user abort handler.
-//!
-//! @param handler A function that takes a const char * argument that will
-//! be called in the event of a abort.
-//--------------------------------------------------------------------------
-
-void
-plsabort( void ( *handler )( const char * ) )
-{
-    abort_handler = handler;
-}
-
-//--------------------------------------------------------------------------
-// void plexit()
-//
-//! In case of an abort this routine is called.  It just prints out an error
-//! message and tries to clean up as much as possible.  It's best to turn
-//! off pause and then restore previous setting before returning.
-//!
-//! If cleanup needs to be done in the main program, the user should write
-//! his/her own exit handler and pass it in via plsexit().  This function
-//! should should either call plend() before exiting, or simply return.
-//!
-//! @param errormsg The error message.
-//--------------------------------------------------------------------------
-
-void
-plexit( const char *errormsg )
-{
-    int status = 1;
-
-    if ( exit_handler != NULL )
-        status = ( *exit_handler )( errormsg );
-
-    plsc->nopause = 1;
-    if ( *errormsg != '\0' )
-    {
-        fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
-        fprintf( stderr, "%s\n", errormsg );
-    }
-    plend();
-
-    fprintf( stderr, "Program aborted\n" );
-    exit( status );
-}
-
-//--------------------------------------------------------------------------
-// void plsexit()
-//
-//! Sets an optional user exit handler.
-//!
-//! @param handler A function that takes a const char * argument that will
-//! will be called in the event of a exit.
-//--------------------------------------------------------------------------
-
-void
-plsexit( int ( *handler )( const char * ) )
-{
-    exit_handler = handler;
-}
-
-//--------------------------------------------------------------------------
 // void plgra()
 //
 //! Switches to graphics screen.
@@ -2528,7 +2347,7 @@ plcol_interp( PLStream *pls, PLColor *newcolor, int i, int ncol )
     delta = x - il;
 
     if ( ir > pls->ncol1 || il < 0 )
-        fprintf( stderr, "Invalid color\n" );
+        plwarn( "Invalid color\n" );
 
     else if ( ir == pls->ncol1 || ( delta == 0. ) )
     {
@@ -2607,7 +2426,7 @@ plOpenFile( PLStream *pls )
             plexit( "Too many tries." );
 
         if ( ( pls->OutFile = fopen( pls->FileName, "wb+" ) ) == NULL )
-            fprintf( stderr, "Can't open %s.\n", pls->FileName );
+            plwarn( "Can't open %s.\n", pls->FileName );
         else
             pldebug( "plOpenFile", "Opened %s\n", pls->FileName );
     }
@@ -3144,9 +2963,7 @@ plrestore_locale( char *saved_lc_numeric_locale )
 
     if ( !( setlocale( LC_NUMERIC, saved_lc_numeric_locale ) ) )
     {
-        char msgbuf[1024];
-        snprintf( msgbuf, 1024, "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
-        plexit( msgbuf );
+        plexit( "plrestore_locale: LC_NUMERIC could not be restored to the default \"%s\" locale.\n", saved_lc_numeric_locale );
     }
     free( saved_lc_numeric_locale );
 }
diff --git a/src/plerror.c b/src/plerror.c
new file mode 100644
index 0000000..b9836be
--- /dev/null
+++ b/src/plerror.c
@@ -0,0 +1,199 @@
+// PLplot error handling routines.  This module provides a uniform method for presenting
+// error and warning messages.  Abnormal exit conditions are handled
+//
+// Copyright (C) 2004  Joao Cardoso
+// Copyright (C) 2004  Rafael Laboissiere
+// Copyright (C) 2008  Hazen Babcock
+// Copyright (C) 2009-2014 Alan W. Irwin
+// Copyright (C) 2011  Hezekiah M. Carty
+// Copyright (C) 2015  Jim Dishaw
+
+//
+// This file is part of PLplot.
+//
+// PLplot is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Library General Public License as published
+// by the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// PLplot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public License
+// along with PLplot; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+//
+
+#include <stdio.h>
+#include "plplotP.h"
+
+static int
+( *exit_handler )( const char *errormsg );
+
+static void
+( *abort_handler )( const char *errormsg );
+
+//--------------------------------------------------------------------------
+// void plwarn()
+//
+//! A handy way to issue warnings, if need be.  This function will add a newline after the message,
+//! thus the caller need not add a newline to errormsg
+//!
+//! @param errormsg The error message.
+
+void
+plwarn( const char *errormsg, ... )
+{
+    va_list args;
+    int was_gfx = 0;
+
+    if ( plsc->graphx == 1 )
+    {
+        was_gfx = 1;
+        pltext();
+    }
+
+    fprintf( stderr, "\n*** PLPLOT WARNING ***\n" );
+    if ( errormsg != NULL && *errormsg != '\0' )
+    {
+        va_start( args, errormsg );
+        vfprintf( stderr, errormsg, args );
+	va_end( args );
+	fputc( '\n', stderr );
+    }
+    
+    if ( was_gfx == 1 )
+        plgra();
+}
+
+//--------------------------------------------------------------------------
+// void plabort()
+//
+//! Much the same as plwarn(), but appends ", aborting operation" to the
+//! error message.  Helps to keep source code uncluttered and provides a
+//! convention for error aborts.
+//!
+//! If cleanup needs to be done in the main program, the user should write
+//! his/her own exit handler and pass it in via plsabort().
+//!
+//! @param errormsg The error message.
+
+void
+plabort( const char *errormsg, ... )
+{
+    va_list args;
+    int nheader, nbody;
+  
+    if ( abort_handler != NULL )
+        ( *abort_handler )( errormsg );
+
+    if ( plsc->errcode != NULL )
+        *( plsc->errcode ) = 1;
+
+    if ( plsc->errmsg != NULL )
+    {
+        // NOTE:  This is bad, bad, bad code because we have no length on errmsg.  Need
+        // to fix this!
+        nheader = sprintf( plsc->errmsg, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
+        if ( errormsg != NULL && *errormsg != '\0' )
+	{
+	    va_start( args, errormsg );
+            nbody = vsprintf( plsc->errmsg + nheader, errormsg, args );
+	    va_end( args );
+	    sprintf( plsc->errmsg + nheader + nbody, ", aborting operation\n" );
+	}
+    }
+    else
+    {
+        int was_gfx = 0;
+
+        if ( plsc->graphx == 1 )
+        {
+            was_gfx = 1;
+            pltext();
+        }
+
+        fprintf( stderr, "\n*** PLPLOT ERROR, ABORTING OPERATION ***\n" );
+        if ( errormsg != NULL && *errormsg != '\0' )
+	{
+  	    va_start( args, errormsg );
+            vfprintf( stderr, errormsg, args );
+	    va_end( args );
+	    fprintf( stderr, ", aborting operation\n" );
+	}
+	
+        if ( was_gfx == 1 )
+            plgra();
+    }
+}
+
+//--------------------------------------------------------------------------
+// void plsabort()
+//
+//! Sets an optional user abort handler.
+//!
+//! @param handler A function that takes a const char * argument that will
+//! be called in the event of a abort.
+//--------------------------------------------------------------------------
+
+void
+plsabort( void ( *handler )( const char * ) )
+{
+    abort_handler = handler;
+}
+
+//--------------------------------------------------------------------------
+// void plexit()
+//
+//! In case of an abort this routine is called.  It just prints out an error
+//! message and tries to clean up as much as possible.  It's best to turn
+//! off pause and then restore previous setting before returning.
+//!
+//! If cleanup needs to be done in the main program, the user should write
+//! his/her own exit handler and pass it in via plsexit().  This function
+//! should should either call plend() before exiting, or simply return.
+//!
+//! @param errormsg The error message.
+//--------------------------------------------------------------------------
+
+void
+plexit( const char *errormsg, ... )
+{
+    va_list args;
+    int status = 1;
+
+    if ( exit_handler != NULL )
+        status = ( *exit_handler )( errormsg );
+
+    plsc->nopause = 1;
+    if ( errormsg != NULL && *errormsg != '\0' )
+    {
+        fprintf( stderr, "\n*** PLPLOT ERROR, IMMEDIATE EXIT ***\n" );
+	va_start( args, errormsg );
+        vfprintf( stderr, errormsg, args );
+	va_end( args );
+	fputc( '\n', stderr );
+    }
+    plend();
+
+    fprintf( stderr, "Program aborted\n" );
+    exit( status );
+}
+
+//--------------------------------------------------------------------------
+// void plsexit()
+//
+//! Sets an optional user exit handler.
+//!
+//! @param handler A function that takes a const char * argument that will
+//! will be called in the event of a exit.
+//--------------------------------------------------------------------------
+
+void
+plsexit( int ( *handler )( const char * ) )
+{
+    exit_handler = handler;
+}
diff --git a/src/plfill.c b/src/plfill.c
index 6a91601..674d693 100644
--- a/src/plfill.c
+++ b/src/plfill.c
@@ -394,7 +394,7 @@ plfill_soft( short *x, short *y, PLINT n )
             i  += 2;
             if ( yp2 != yp1 )
             {
-                fprintf( stderr, "plfill: oh oh we are lost\n" );
+                plwarn( "plfill: oh oh we are lost\n" );
                 for ( j = 0; j < bufferleng; j += 2 )
                 {
                     fprintf( stderr, "plfill: %d %d\n",
diff --git a/src/plmap.c b/src/plmap.c
index d843acd..f6193be 100644
--- a/src/plmap.c
+++ b/src/plmap.c
@@ -896,7 +896,7 @@ static
 void CustomErrors( const char *message )
 {
     if ( strstr( message, "Unable to open" ) == NULL )
-        fprintf( stderr, "%s\n", message );
+        plwarn( "%s", message );
 }
 #endif
 
diff --git a/src/plshade.c b/src/plshade.c
index 8dd04fd..4499d58 100644
--- a/src/plshade.c
+++ b/src/plshade.c
@@ -700,7 +700,7 @@ plshade_int( PLFLT ( *f2eval )( PLINT, PLINT, PLPointer ),
             case 040:   // 2 contour lines in box
             case 004:
                 if ( n != 6 )
-                    fprintf( stderr, "plfshade err n=%d !6", (int) n );
+                    plwarn( "plfshade err n=%d !6", (int) n );
                 if ( slope == 1 && c0[iy] == OK )
                 {
                     if ( fill != NULL )
diff --git a/src/plvect.c b/src/plvect.c
index a77e81b..5fdc735 100644
--- a/src/plvect.c
+++ b/src/plvect.c
@@ -163,7 +163,7 @@ void plfvect( PLFLT ( *getuv )( PLINT, PLINT, PLPointer ),
     {
         if ( nx <= 1 && ny <= 1 )
         {
-            fprintf( stderr, "plfvect: not enough points for autoscaling\n" );
+            plwarn( "plfvect: not enough points for autoscaling\n" );
             return;
         }
         dxmin = 10E10;
-- 
2.3.2 (Apple Git-55)

