1 /**********************************************************************
2  * $Id: cpl_error.c,v 1.3 2005/06/03 03:49:59 daniel Exp $
3  *
4  * Name:     cpl_error.cpp
5  * Project:  CPL - Common Portability Library
6  * Purpose:  Error handling functions.
7  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
8  *
9  **********************************************************************
10  * Copyright (c) 1998, Daniel Morissette
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  **********************************************************************
30  *
31  * $Log: cpl_error.c,v $
32  * Revision 1.3  2005/06/03 03:49:59  daniel
33  * Update email address, website url, and copyright dates
34  *
35  * Revision 1.2  1999/11/23 04:18:45  daniel
36  * Fixed var. initialization that failed to compile in C
37  *
38  * Revision 1.1  1999/08/27 14:09:55  daniel
39  * Update CPL files
40  *
41  * Revision 1.8  1999/07/23 14:27:47  warmerda
42  * CPLSetErrorHandler returns old handler
43  *
44  * Revision 1.7  1999/06/27 16:50:52  warmerda
45  * added support for CPL_DEBUG and CPL_LOG variables
46  *
47  * Revision 1.6  1999/06/26 02:46:11  warmerda
48  * Fixed initialization of debug messages.
49  *
50  * Revision 1.5  1999/05/20 14:59:05  warmerda
51  * added CPLDebug()
52  *
53  * Revision 1.4  1999/05/20 02:54:38  warmerda
54  * Added API documentation
55  *
56  * Revision 1.3  1998/12/15 19:02:27  warmerda
57  * Avoid use of errno as a variable
58  *
59  * Revision 1.2  1998/12/06 02:52:52  warmerda
60  * Implement assert support
61  *
62  * Revision 1.1  1998/12/03 18:26:02  warmerda
63  * New
64  *
65  **********************************************************************/
66 
67 #include "cpl_error.h"
68 #include "cpl_vsi.h"
69 
70 /* static buffer to store the last error message.  We'll assume that error
71  * messages cannot be longer than 2000 chars... which is quite reasonable
72  * (that's 25 lines of 80 chars!!!)
73  */
74 static char gszCPLLastErrMsg[2000] = "";
75 static int  gnCPLLastErrNo = 0;
76 
77 static void CPLDefaultErrorHandler( CPLErr, int, const char *);
78 static CPLErrorHandler gpfnCPLErrorHandler = CPLDefaultErrorHandler;
79 
80 /**********************************************************************
81  *                          CPLError()
82  **********************************************************************/
83 
84 /**
85  * Report an error.
86  *
87  * This function reports an error in a manner that can be hooked
88  * and reported appropriate by different applications.
89  *
90  * The effect of this function can be altered by applications by installing
91  * a custom error handling using CPLSetErrorHandler().
92  *
93  * The eErrClass argument can have the value CE_Warning indicating that the
94  * message is an informational warning, CE_Failure indicating that the
95  * action failed, but that normal recover mechanisms will be used or
96  * CE_Fatal meaning that a fatal error has occured, and that CPLError()
97  * should not return.
98  *
99  * The default behaviour of CPLError() is to report errors to stderr,
100  * and to abort() after reporting a CE_Fatal error.  It is expected that
101  * some applications will want to supress error reporting, and will want to
102  * install a C++ exception, or longjmp() approach to no local fatal error
103  * recovery.
104  *
105  * Regardless of how application error handlers or the default error
106  * handler choose to handle an error, the error number, and message will
107  * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
108  *
109  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
110  * @param err_no the error number (CPLE_*) from cpl_error.h.
111  * @param fmt a printf() style format string.  Any additional arguments
112  * will be treated as arguments to fill in this format in a manner
113  * similar to printf().
114  */
115 
CPLError(CPLErr eErrClass,int err_no,const char * fmt,...)116 void    CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...)
117 {
118     va_list args;
119 
120     /* Expand the error message
121      */
122     va_start(args, fmt);
123     vsprintf(gszCPLLastErrMsg, fmt, args);
124     va_end(args);
125 
126     /* If the user provided his own error handling function, then call
127      * it, otherwise print the error to stderr and return.
128      */
129     gnCPLLastErrNo = err_no;
130 
131     if( gpfnCPLErrorHandler )
132         gpfnCPLErrorHandler(eErrClass, err_no, gszCPLLastErrMsg);
133 
134     if( eErrClass == CE_Fatal )
135         abort();
136 }
137 
138 /************************************************************************/
139 /*                              CPLDebug()                              */
140 /************************************************************************/
141 
142 /**
143  * Display a debugging message.
144  *
145  * The category argument is used in conjunction with the CPL_DEBUG
146  * environment variable to establish if the message should be displayed.
147  * If the CPL_DEBUG environment variable is not set, no debug messages
148  * are emitted (use CPLError(CE_Warning,...) to ensure messages are displayed).
149  * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
150  * debug messages are shown.  Otherwise only messages whose category appears
151  * somewhere within the CPL_DEBUG value are displayed (as determinted by
152  * strstr()).
153  *
154  * Categories are usually an identifier for the subsystem producing the
155  * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
156  * for messages from the TIFF translator.
157  *
158  * @param pszCategory name of the debugging message category.
159  * @param pszFormat printf() style format string for message to display.
160  *        Remaining arguments are assumed to be for format.
161  */
162 
CPLDebug(const char * pszCategory,const char * pszFormat,...)163 void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
164 
165 {
166     char	*pszMessage;
167     va_list args;
168     const char      *pszDebug = getenv("CPL_DEBUG");
169 
170 /* -------------------------------------------------------------------- */
171 /*      Does this message pass our current criteria?                    */
172 /* -------------------------------------------------------------------- */
173     if( pszDebug == NULL )
174         return;
175 
176     if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") )
177     {
178         int            i, nLen = strlen(pszCategory);
179 
180         for( i = 0; pszDebug[i] != '\0'; i++ )
181         {
182             if( EQUALN(pszCategory,pszDebug+i,nLen) )
183                 break;
184         }
185 
186         if( pszDebug[i] == '\0' )
187             return;
188     }
189 
190 /* -------------------------------------------------------------------- */
191 /*      Format the error message                                        */
192 /* -------------------------------------------------------------------- */
193     pszMessage = (char *) VSIMalloc(25000);
194     if( pszMessage == NULL )
195         return;
196 
197     strcpy( pszMessage, pszCategory );
198     strcat( pszMessage, ": " );
199 
200     va_start(args, pszFormat);
201     vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
202     va_end(args);
203 
204 /* -------------------------------------------------------------------- */
205 /*      If the user provided his own error handling function, then call */
206 /*      it, otherwise print the error to stderr and return.             */
207 /* -------------------------------------------------------------------- */
208     if( gpfnCPLErrorHandler )
209         gpfnCPLErrorHandler(CE_Debug, CPLE_None, pszMessage);
210 
211     VSIFree( pszMessage );
212 }
213 
214 /**********************************************************************
215  *                          CPLErrorReset()
216  **********************************************************************/
217 
218 /**
219  * Erase any traces of previous errors.
220  *
221  * This is normally used to ensure that an error which has been recovered
222  * from does not appear to be still in play with high level functions.
223  */
224 
CPLErrorReset()225 void    CPLErrorReset()
226 {
227     gnCPLLastErrNo = CPLE_None;
228     gszCPLLastErrMsg[0] = '\0';
229 }
230 
231 
232 /**********************************************************************
233  *                          CPLGetLastErrorNo()
234  **********************************************************************/
235 
236 /**
237  * Fetch the last error number.
238  *
239  * This is the error number, not the error class.
240  *
241  * @return the error number of the last error to occur, or CPLE_None (0)
242  * if there are no posted errors.
243  */
244 
CPLGetLastErrorNo()245 int     CPLGetLastErrorNo()
246 {
247     return gnCPLLastErrNo;
248 }
249 
250 /**********************************************************************
251  *                          CPLGetLastErrorMsg()
252  **********************************************************************/
253 
254 /**
255  * Get the last error message.
256  *
257  * Fetches the last error message posted with CPLError(), that hasn't
258  * been cleared by CPLErrorReset().  The returned pointer is to an internal
259  * string that should not be altered or freed.
260  *
261  * @return the last error message, or NULL if there is no posted error
262  * message.
263  */
264 
CPLGetLastErrorMsg()265 const char* CPLGetLastErrorMsg()
266 {
267     return gszCPLLastErrMsg;
268 }
269 
270 /************************************************************************/
271 /*                       CPLDefaultErrorHandler()                       */
272 /************************************************************************/
273 
CPLDefaultErrorHandler(CPLErr eErrClass,int nError,const char * pszErrorMsg)274 static void CPLDefaultErrorHandler( CPLErr eErrClass, int nError,
275                                     const char * pszErrorMsg )
276 
277 {
278     static int       bLogInit = FALSE;
279     static FILE *    fpLog;
280 
281     fpLog = stderr;
282 
283     if( !bLogInit )
284     {
285         bLogInit = TRUE;
286 
287         if( getenv( "CPL_LOG" ) != NULL )
288         {
289             fpLog = fopen( getenv("CPL_LOg"), "wt" );
290             if( fpLog == NULL )
291                 fpLog = stderr;
292         }
293     }
294 
295     if( eErrClass == CE_Debug )
296         fprintf( fpLog, "%s\n", pszErrorMsg );
297     else if( eErrClass == CE_Warning )
298         fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
299     else
300         fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
301 
302     fflush( fpLog );
303 }
304 
305 
306 /**********************************************************************
307  *                          CPLSetErrorHandler()
308  **********************************************************************/
309 
310 /**
311  * Install custom error handler.
312  *
313  * Allow the library's user to specify his own error handler function.
314  * A valid error handler is a C function with the following prototype:
315  *
316  * <pre>
317  *     void MyErrorHandler(CPLErr eErrClass, int errno, const char *msg)
318  * </pre>
319  *
320  * Pass NULL to come back to the default behavior.  The default behaviour
321  * is to write the message to
322  *
323  * The msg will be a partially formatted error message not containing the
324  * "ERROR %d:" portion emitted by the default handler.  Message formatting
325  * is handled by CPLError() before calling the handler.  If the error
326  * handler function is passed a CE_Fatal class error and returns, then
327  * CPLError() will call abort(). Applications wanting to interrupt this
328  * fatal behaviour will have to use longjmp(), or a C++ exception to
329  * indirectly exit the function.
330  *
331  * @param pfnErrorHandler new error handler function.
332  * @return returns the previously installed error handler.
333  */
334 
CPLSetErrorHandler(CPLErrorHandler pfnErrorHandler)335 CPLErrorHandler CPLSetErrorHandler( CPLErrorHandler pfnErrorHandler )
336 {
337     CPLErrorHandler	pfnOldHandler = gpfnCPLErrorHandler;
338 
339     gpfnCPLErrorHandler = pfnErrorHandler;
340 
341     return pfnOldHandler;
342 }
343 
344 /************************************************************************/
345 /*                             _CPLAssert()                             */
346 /*                                                                      */
347 /*      This function is called only when an assertion fails.           */
348 /************************************************************************/
349 
350 /**
351  * Report failure of a logical assertion.
352  *
353  * Applications would normally use the CPLAssert() macro which expands
354  * into code calling _CPLAssert() only if the condition fails.  _CPLAssert()
355  * will generate a CE_Fatal error call to CPLError(), indicating the file
356  * name, and line number of the failed assertion, as well as containing
357  * the assertion itself.
358  *
359  * There is no reason for application code to call _CPLAssert() directly.
360  */
361 
_CPLAssert(const char * pszExpression,const char * pszFile,int iLine)362 void _CPLAssert( const char * pszExpression, const char * pszFile,
363                  int iLine )
364 
365 {
366     CPLError( CE_Fatal, CPLE_AssertionFailed,
367               "Assertion `%s' failed\n"
368               "in file `%s', line %d\n",
369               pszExpression, pszFile, iLine );
370 }
371 
372