Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages  

cpl_error.cpp

00001 /**********************************************************************
00002  * $Id: cpl_error_cpp-source.html,v 1.13 2002/12/21 19:13:12 warmerda Exp $
00003  *
00004  * Name:     cpl_error.cpp
00005  * Project:  CPL - Common Portability Library
00006  * Purpose:  Error handling functions.
00007  * Author:   Daniel Morissette, danmo@videotron.ca
00008  *
00009  **********************************************************************
00010  * Copyright (c) 1998, Daniel Morissette
00011  *
00012  * Permission is hereby granted, free of charge, to any person obtaining a
00013  * copy of this software and associated documentation files (the "Software"),
00014  * to deal in the Software without restriction, including without limitation
00015  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00016  * and/or sell copies of the Software, and to permit persons to whom the
00017  * Software is furnished to do so, subject to the following conditions:
00018  * 
00019  * The above copyright notice and this permission notice shall be included
00020  * in all copies or substantial portions of the Software.
00021  * 
00022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00025  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00027  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
00028  * DEALINGS IN THE SOFTWARE.
00029  **********************************************************************
00030  *
00031  * $Log: cpl_error_cpp-source.html,v $
00031  * Revision 1.13  2002/12/21 19:13:12  warmerda
00031  * updated
00031  *
00032  * Revision 1.23  2002/10/23 20:19:37  warmerda
00033  * Modify log file naming convention as per patch from Dale.
00034  *
00035  * Revision 1.22  2002/08/01 20:02:54  warmerda
00036  * added CPL_LOG_ERRORS support
00037  *
00038  * Revision 1.21  2001/12/14 19:45:17  warmerda
00039  * Avoid use of errno in prototype.
00040  *
00041  * Revision 1.20  2001/11/27 17:01:06  warmerda
00042  * added timestamp to debug messages
00043  *
00044  * Revision 1.19  2001/11/15 16:11:08  warmerda
00045  * use vsnprintf() for debug calls if it is available
00046  *
00047  * Revision 1.18  2001/11/02 22:07:58  warmerda
00048  * added logging error handler
00049  *
00050  * Revision 1.17  2001/07/18 04:00:49  warmerda
00051  * added CPL_CVSID
00052  *
00053  * Revision 1.16  2001/02/15 16:30:57  warmerda
00054  * fixed initialization of fpLog
00055  *
00056  * Revision 1.15  2001/01/19 21:16:41  warmerda
00057  * expanded tabs
00058  *
00059  * Revision 1.14  2000/11/30 17:30:10  warmerda
00060  * added CPLGetLastErrorType
00061  *
00062  * Revision 1.13  2000/03/31 14:37:48  warmerda
00063  * only use vsnprintf where available
00064  *
00065  * Revision 1.12  2000/03/31 14:11:55  warmerda
00066  * added CPLErrorV
00067  *
00068  * Revision 1.11  2000/01/10 17:35:45  warmerda
00069  * added push down stack of error handlers
00070  *
00071  * Revision 1.10  1999/11/23 04:16:56  danmo
00072  * Fixed var. initialization that failed to compile as C
00073  *
00074  * Revision 1.9  1999/09/03 17:03:45  warmerda
00075  * Completed partial help line.
00076  *
00077  * Revision 1.8  1999/07/23 14:27:47  warmerda
00078  * CPLSetErrorHandler returns old handler
00079  *
00080  * Revision 1.7  1999/06/27 16:50:52  warmerda
00081  * added support for CPL_DEBUG and CPL_LOG variables
00082  *
00083  * Revision 1.6  1999/06/26 02:46:11  warmerda
00084  * Fixed initialization of debug messages.
00085  *
00086  * Revision 1.5  1999/05/20 14:59:05  warmerda
00087  * added CPLDebug()
00088  *
00089  * Revision 1.4  1999/05/20 02:54:38  warmerda
00090  * Added API documentation
00091  *
00092  * Revision 1.3  1998/12/15 19:02:27  warmerda
00093  * Avoid use of errno as a variable
00094  *
00095  * Revision 1.2  1998/12/06 02:52:52  warmerda
00096  * Implement assert support
00097  *
00098  * Revision 1.1  1998/12/03 18:26:02  warmerda
00099  * New
00100  *
00101  **********************************************************************/
00102 
00103 #include "cpl_error.h"
00104 #include "cpl_vsi.h"
00105 
00106 #define TIMESTAMP_DEBUG
00107 #ifdef TIMESTAMP_DEBUG
00108 #include <time.h>
00109 #endif
00110 
00111 CPL_CVSID("$Id: cpl_error_cpp-source.html,v 1.13 2002/12/21 19:13:12 warmerda Exp $");
00112 
00113 /* static buffer to store the last error message.  We'll assume that error
00114  * messages cannot be longer than 2000 chars... which is quite reasonable
00115  * (that's 25 lines of 80 chars!!!)
00116  */
00117 static char gszCPLLastErrMsg[2000] = "";
00118 static int  gnCPLLastErrNo = 0;
00119 static CPLErr geCPLLastErrType = CE_None;
00120 
00121 static CPLErrorHandler gpfnCPLErrorHandler = CPLDefaultErrorHandler;
00122 
00123 typedef struct errHandler
00124 {
00125     struct errHandler   *psNext;
00126     CPLErrorHandler     pfnHandler;
00127 } CPLErrorHandlerNode;
00128 
00129 static CPLErrorHandlerNode * psHandlerStack = NULL;
00130 
00131 /**********************************************************************
00132  *                          CPLError()
00133  **********************************************************************/
00134 
00167 void    CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...)
00168 {
00169     va_list args;
00170 
00171     /* Expand the error message 
00172      */
00173     va_start(args, fmt);
00174     CPLErrorV( eErrClass, err_no, fmt, args );
00175     va_end(args);
00176 }
00177 
00178 /************************************************************************/
00179 /*                             CPLErrorV()                              */
00180 /************************************************************************/
00181 
00182 void    CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
00183 {
00184     /* Expand the error message 
00185      */
00186 #if defined(HAVE_VSNPRINTF)
00187     vsnprintf(gszCPLLastErrMsg, sizeof(gszCPLLastErrMsg), fmt, args);
00188 #else
00189     vsprintf(gszCPLLastErrMsg, fmt, args);
00190 #endif
00191 
00192     /* If the user provided his own error handling function, then call
00193      * it, otherwise print the error to stderr and return.
00194      */
00195     gnCPLLastErrNo = err_no;
00196     geCPLLastErrType = eErrClass;
00197 
00198     if( getenv("CPL_LOG_ERRORS") != NULL )
00199         CPLDebug( "CPLError", "%s", gszCPLLastErrMsg );
00200 
00201     if( gpfnCPLErrorHandler )
00202         gpfnCPLErrorHandler(eErrClass, err_no, gszCPLLastErrMsg);
00203 
00204     if( eErrClass == CE_Fatal )
00205         abort();
00206 }
00207 
00208 /************************************************************************/
00209 /*                              CPLDebug()                              */
00210 /************************************************************************/
00211 
00233 void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
00234 
00235 {
00236     char        *pszMessage;
00237     va_list args;
00238     const char      *pszDebug = getenv("CPL_DEBUG");
00239 
00240 #define ERROR_MAX 25000
00241 
00242 /* -------------------------------------------------------------------- */
00243 /*      Does this message pass our current criteria?                    */
00244 /* -------------------------------------------------------------------- */
00245     if( pszDebug == NULL )
00246         return;
00247 
00248     if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") )
00249     {
00250         int            i, nLen = strlen(pszCategory);
00251 
00252         for( i = 0; pszDebug[i] != '\0'; i++ )
00253         {
00254             if( EQUALN(pszCategory,pszDebug+i,nLen) )
00255                 break;
00256         }
00257 
00258         if( pszDebug[i] == '\0' )
00259             return;
00260     }
00261 
00262 /* -------------------------------------------------------------------- */
00263 /*    Allocate a block for the error.                                   */
00264 /* -------------------------------------------------------------------- */
00265     pszMessage = (char *) VSIMalloc(ERROR_MAX);
00266     if( pszMessage == NULL )
00267         return;
00268         
00269 /* -------------------------------------------------------------------- */
00270 /*      Dal -- always log a timestamp as the first part of the line     */
00271 /*      to ensure one is looking at what one should be looking at!      */
00272 /* -------------------------------------------------------------------- */
00273 
00274 #ifdef TIMESTAMP_DEBUG
00275     {
00276         time_t ltime;
00277     
00278         time( &ltime );
00279         strcpy( pszMessage, ctime( &ltime ) );
00280         
00281         // On windows anyway, ctime puts a \n at the end, but I'm not 
00282         // convinced this is standard behaviour, so we'll get rid of it
00283         // carefully
00284 
00285         if (pszMessage[strlen(pszMessage) -1 ] == '\n')
00286         {
00287             pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
00288         }
00289         strcat( pszMessage, ": " );
00290     }
00291 #else
00292     pszMessage[0] = '\0';
00293 #endif
00294 
00295 /* -------------------------------------------------------------------- */
00296 /*      Add the category.                                               */
00297 /* -------------------------------------------------------------------- */
00298     strcat( pszMessage, pszCategory );
00299     strcat( pszMessage, ": " );
00300     
00301 /* -------------------------------------------------------------------- */
00302 /*      Format the application provided portion of the debug message.   */
00303 /* -------------------------------------------------------------------- */
00304     va_start(args, pszFormat);
00305 #if defined(HAVE_VSNPRINTF)
00306     vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage), 
00307               pszFormat, args);
00308 #else
00309     vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
00310 #endif
00311     va_end(args);
00312 
00313 /* -------------------------------------------------------------------- */
00314 /*      If the user provided his own error handling function, then call */
00315 /*      it, otherwise print the error to stderr and return.             */
00316 /* -------------------------------------------------------------------- */
00317     if( gpfnCPLErrorHandler )
00318         gpfnCPLErrorHandler(CE_Debug, CPLE_None, pszMessage);
00319 
00320     VSIFree( pszMessage );
00321 }
00322 
00323 /**********************************************************************
00324  *                          CPLErrorReset()
00325  **********************************************************************/
00326 
00334 void    CPLErrorReset()
00335 {
00336     gnCPLLastErrNo = CPLE_None;
00337     gszCPLLastErrMsg[0] = '\0';
00338     geCPLLastErrType = CE_None;
00339 }
00340 
00341 
00342 /**********************************************************************
00343  *                          CPLGetLastErrorNo()
00344  **********************************************************************/
00345 
00355 int     CPLGetLastErrorNo()
00356 {
00357     return gnCPLLastErrNo;
00358 }
00359 
00360 /**********************************************************************
00361  *                          CPLGetLastErrorType()
00362  **********************************************************************/
00363 
00373 CPLErr CPLGetLastErrorType()
00374 {
00375     return geCPLLastErrType;
00376 }
00377 
00378 /**********************************************************************
00379  *                          CPLGetLastErrorMsg()
00380  **********************************************************************/
00381 
00393 const char* CPLGetLastErrorMsg()
00394 {
00395     return gszCPLLastErrMsg;
00396 }
00397 
00398 /************************************************************************/
00399 /*                       CPLDefaultErrorHandler()                       */
00400 /************************************************************************/
00401 
00402 void CPLDefaultErrorHandler( CPLErr eErrClass, int nError, 
00403                              const char * pszErrorMsg )
00404 
00405 {
00406     static int       bLogInit = FALSE;
00407     static FILE *    fpLog = stderr;
00408 
00409     if( !bLogInit )
00410     {
00411         bLogInit = TRUE;
00412 
00413         fpLog = stderr;
00414         if( getenv( "CPL_LOG" ) != NULL )
00415         {
00416             fpLog = fopen( getenv("CPL_LOG"), "wt" );
00417             if( fpLog == NULL )
00418                 fpLog = stderr;
00419         }
00420     }
00421 
00422     if( eErrClass == CE_Debug )
00423         fprintf( fpLog, "%s\n", pszErrorMsg );
00424     else if( eErrClass == CE_Warning )
00425         fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
00426     else
00427         fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
00428 
00429     fflush( fpLog );
00430 }
00431 
00432 /************************************************************************/
00433 /*                        CPLQuietErrorHandler()                        */
00434 /************************************************************************/
00435 
00436 void CPLQuietErrorHandler( CPLErr eErrClass , int nError, 
00437                            const char * pszErrorMsg )
00438 
00439 {
00440     if( eErrClass == CE_Debug )
00441         CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg );
00442 }
00443 
00444 /************************************************************************/
00445 /*                       CPLLoggingErrorHandler()                       */
00446 /************************************************************************/
00447 
00448 void CPLLoggingErrorHandler( CPLErr eErrClass, int nError, 
00449                              const char * pszErrorMsg )
00450 
00451 {
00452     static int       bLogInit = FALSE;
00453     static FILE *    fpLog = stderr;
00454 
00455     if( !bLogInit )
00456     {
00457         const char *cpl_log = NULL;
00458 
00459         bLogInit = TRUE;
00460 
00461         if( getenv("CPL_LOG") != NULL )
00462             cpl_log = getenv("CPL_LOG");
00463 
00464         fpLog = stderr;
00465         if( cpl_log != NULL && EQUAL(cpl_log,"OFF") )
00466         {
00467             fpLog = NULL;
00468         }
00469         else if( cpl_log != NULL )
00470         {
00471             char      path[5000];
00472             int       i = 0;
00473 
00474             strcpy( path, cpl_log );
00475 
00476             while( (fpLog = fopen( path, "rt" )) != NULL ) 
00477             {
00478                 fclose( fpLog );
00479 
00480                 /* generate sequenced log file names, inserting # before ext.*/
00481                 if (strrchr(cpl_log, '.') == NULL)
00482                 {
00483                     sprintf( path, "%s_%d%s", cpl_log, i++,
00484                              ".log" );
00485                 }
00486                 else
00487                 {
00488                     int pos = 0;
00489                     char *cpl_log_base = strdup(cpl_log);
00490                     pos = strcspn(cpl_log_base, ".");
00491                     if (pos > 0)
00492                     {
00493                         cpl_log_base[pos] = '\0';
00494                     }
00495                     sprintf( path, "%s_%d%s", cpl_log_base,
00496                              i++, ".log" );
00497                 }
00498             }
00499 
00500             fpLog = fopen( path, "wt" );
00501         }
00502     }
00503 
00504     if( fpLog == NULL )
00505         return;
00506 
00507     if( eErrClass == CE_Debug )
00508         fprintf( fpLog, "%s\n", pszErrorMsg );
00509     else if( eErrClass == CE_Warning )
00510         fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
00511     else
00512         fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
00513 
00514     fflush( fpLog );
00515 }
00516 
00517 /**********************************************************************
00518  *                          CPLSetErrorHandler()
00519  **********************************************************************/
00520 
00550 CPLErrorHandler CPLSetErrorHandler( CPLErrorHandler pfnErrorHandler )
00551 {
00552     CPLErrorHandler     pfnOldHandler = gpfnCPLErrorHandler;
00553     
00554     gpfnCPLErrorHandler = pfnErrorHandler;
00555 
00556     return pfnOldHandler;
00557 }
00558 
00559 
00560 
00561 /************************************************************************/
00562 /*                        CPLPushErrorHandler()                         */
00563 /************************************************************************/
00564 
00576 void CPLPushErrorHandler( CPLErrorHandler pfnErrorHandler )
00577 
00578 {
00579     CPLErrorHandlerNode         *psNode;
00580 
00581     psNode = (CPLErrorHandlerNode *) VSIMalloc(sizeof(CPLErrorHandlerNode));
00582     psNode->psNext = psHandlerStack;
00583     psNode->pfnHandler = gpfnCPLErrorHandler;
00584 
00585     psHandlerStack = psNode;
00586 
00587     CPLSetErrorHandler( pfnErrorHandler );
00588 }
00589 
00590 /************************************************************************/
00591 /*                         CPLPopErrorHandler()                         */
00592 /************************************************************************/
00593 
00601 void CPLPopErrorHandler()
00602 
00603 {
00604     if( psHandlerStack != NULL )
00605     {
00606         CPLErrorHandlerNode     *psNode = psHandlerStack;
00607 
00608         psHandlerStack = psNode->psNext;
00609         CPLSetErrorHandler( psNode->pfnHandler );
00610         VSIFree( psNode );
00611     }
00612 }
00613 
00614 /************************************************************************/
00615 /*                             _CPLAssert()                             */
00616 /*                                                                      */
00617 /*      This function is called only when an assertion fails.           */
00618 /************************************************************************/
00619 
00632 void _CPLAssert( const char * pszExpression, const char * pszFile,
00633                  int iLine )
00634 
00635 {
00636     CPLError( CE_Fatal, CPLE_AssertionFailed,
00637               "Assertion `%s' failed\n"
00638               "in file `%s', line %d\n",
00639               pszExpression, pszFile, iLine );
00640 }
00641 

Generated at Sat Dec 21 14:01:57 2002 for GDAL by doxygen1.2.3-20001105 written by Dimitri van Heesch, © 1997-2000