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