1 : /**********************************************************************
2 : * $Id: cpl_error.cpp 19588 2010-04-30 19:56:38Z rouault $
3 : *
4 : * Name: cpl_error.cpp
5 : * Project: CPL - Common Portability Library
6 : * Purpose: Error handling functions.
7 : * Author: Daniel Morissette, danmo@videotron.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 : #include "cpl_error.h"
32 : #include "cpl_vsi.h"
33 : #include "cpl_conv.h"
34 : #include "cpl_multiproc.h"
35 :
36 : #if defined(WIN32CE)
37 : # include "cpl_wince.h"
38 : # include <wce_stdlib.h>
39 : #endif
40 :
41 : #define TIMESTAMP_DEBUG
42 :
43 : CPL_CVSID("$Id: cpl_error.cpp 19588 2010-04-30 19:56:38Z rouault $");
44 :
45 : static void *hErrorMutex = NULL;
46 : static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
47 :
48 : #if !defined(HAVE_VSNPRINTF)
49 : # define DEFAULT_LAST_ERR_MSG_SIZE 20000
50 : #else
51 : # define DEFAULT_LAST_ERR_MSG_SIZE 500
52 : #endif
53 :
54 : typedef struct errHandler
55 : {
56 : struct errHandler *psNext;
57 : CPLErrorHandler pfnHandler;
58 : } CPLErrorHandlerNode;
59 :
60 : typedef struct {
61 : int nLastErrNo;
62 : CPLErr eLastErrType;
63 : CPLErrorHandlerNode *psHandlerStack;
64 : int nLastErrMsgMax;
65 : int nFailureIntoWarning;
66 : char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
67 : /* Do not add anything here. szLastErrMsg must be the last field. See CPLRealloc() below */
68 : } CPLErrorContext;
69 :
70 : /************************************************************************/
71 : /* CPLGetErrorContext() */
72 : /************************************************************************/
73 :
74 1547655 : static CPLErrorContext *CPLGetErrorContext()
75 :
76 : {
77 : CPLErrorContext *psCtx =
78 1547655 : (CPLErrorContext *) CPLGetTLS( CTLS_ERRORCONTEXT );
79 :
80 1547655 : if( psCtx == NULL )
81 : {
82 435 : psCtx = (CPLErrorContext *) CPLCalloc(sizeof(CPLErrorContext),1);
83 435 : psCtx->eLastErrType = CE_None;
84 435 : psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
85 435 : CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
86 : }
87 :
88 1547655 : return psCtx;
89 : }
90 :
91 :
92 : /**********************************************************************
93 : * CPLError()
94 : **********************************************************************/
95 :
96 : /**
97 : * Report an error.
98 : *
99 : * This function reports an error in a manner that can be hooked
100 : * and reported appropriate by different applications.
101 : *
102 : * The effect of this function can be altered by applications by installing
103 : * a custom error handling using CPLSetErrorHandler().
104 : *
105 : * The eErrClass argument can have the value CE_Warning indicating that the
106 : * message is an informational warning, CE_Failure indicating that the
107 : * action failed, but that normal recover mechanisms will be used or
108 : * CE_Fatal meaning that a fatal error has occured, and that CPLError()
109 : * should not return.
110 : *
111 : * The default behaviour of CPLError() is to report errors to stderr,
112 : * and to abort() after reporting a CE_Fatal error. It is expected that
113 : * some applications will want to supress error reporting, and will want to
114 : * install a C++ exception, or longjmp() approach to no local fatal error
115 : * recovery.
116 : *
117 : * Regardless of how application error handlers or the default error
118 : * handler choose to handle an error, the error number, and message will
119 : * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
120 : *
121 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
122 : * @param err_no the error number (CPLE_*) from cpl_error.h.
123 : * @param fmt a printf() style format string. Any additional arguments
124 : * will be treated as arguments to fill in this format in a manner
125 : * similar to printf().
126 : */
127 :
128 15947 : void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...)
129 : {
130 : va_list args;
131 :
132 : /* Expand the error message
133 : */
134 15947 : va_start(args, fmt);
135 15947 : CPLErrorV( eErrClass, err_no, fmt, args );
136 15947 : va_end(args);
137 15947 : }
138 :
139 : /************************************************************************/
140 : /* CPLErrorV() */
141 : /************************************************************************/
142 :
143 15947 : void CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
144 : {
145 15947 : CPLErrorContext *psCtx = CPLGetErrorContext();
146 :
147 15947 : if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
148 0 : eErrClass = CE_Warning;
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Expand the error message */
152 : /* -------------------------------------------------------------------- */
153 : #if defined(HAVE_VSNPRINTF)
154 : {
155 : int nPR;
156 : va_list wrk_args;
157 :
158 : #ifdef va_copy
159 15947 : va_copy( wrk_args, args );
160 : #else
161 : wrk_args = args;
162 : #endif
163 :
164 : /* -------------------------------------------------------------------- */
165 : /* If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages, */
166 : /* rather than just replacing the last error message. */
167 : /* -------------------------------------------------------------------- */
168 15947 : int nPreviousSize = 0;
169 15947 : if ( psCtx->psHandlerStack != NULL &&
170 : EQUAL(CPLGetConfigOption( "CPL_ACCUM_ERROR_MSG", "" ), "ON"))
171 : {
172 0 : nPreviousSize = strlen(psCtx->szLastErrMsg);
173 0 : if (nPreviousSize)
174 : {
175 0 : if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
176 : {
177 0 : psCtx->nLastErrMsgMax *= 3;
178 : psCtx = (CPLErrorContext *)
179 0 : CPLRealloc(psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE + psCtx->nLastErrMsgMax + 1);
180 0 : CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
181 : }
182 0 : psCtx->szLastErrMsg[nPreviousSize] = '\n';
183 0 : psCtx->szLastErrMsg[nPreviousSize+1] = '0';
184 0 : nPreviousSize ++;
185 : }
186 : }
187 :
188 31894 : while( ((nPR = vsnprintf( psCtx->szLastErrMsg+nPreviousSize,
189 : psCtx->nLastErrMsgMax-nPreviousSize, fmt, wrk_args )) == -1
190 : || nPR >= psCtx->nLastErrMsgMax-nPreviousSize-1)
191 : && psCtx->nLastErrMsgMax < 1000000 )
192 : {
193 : #ifdef va_copy
194 0 : va_end( wrk_args );
195 0 : va_copy( wrk_args, args );
196 : #else
197 : wrk_args = args;
198 : #endif
199 0 : psCtx->nLastErrMsgMax *= 3;
200 : psCtx = (CPLErrorContext *)
201 0 : CPLRealloc(psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE + psCtx->nLastErrMsgMax + 1);
202 0 : CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
203 : }
204 :
205 15947 : va_end( wrk_args );
206 : }
207 : #else
208 : vsprintf( psCtx->szLastErrMsg, fmt, args);
209 : #endif
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* If the user provided his own error handling function, then */
213 : /* call it, otherwise print the error to stderr and return. */
214 : /* -------------------------------------------------------------------- */
215 15947 : psCtx->nLastErrNo = err_no;
216 15947 : psCtx->eLastErrType = eErrClass;
217 :
218 15947 : if( CPLGetConfigOption("CPL_LOG_ERRORS",NULL) != NULL )
219 0 : CPLDebug( "CPLError", "%s", psCtx->szLastErrMsg );
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Invoke the current error handler. */
223 : /* -------------------------------------------------------------------- */
224 15947 : if( psCtx->psHandlerStack != NULL )
225 : {
226 : psCtx->psHandlerStack->pfnHandler(eErrClass, err_no,
227 15900 : psCtx->szLastErrMsg);
228 : }
229 : else
230 : {
231 47 : CPLMutexHolderD( &hErrorMutex );
232 47 : if( pfnErrorHandler != NULL )
233 47 : pfnErrorHandler(eErrClass, err_no, psCtx->szLastErrMsg);
234 : }
235 :
236 15947 : if( eErrClass == CE_Fatal )
237 0 : abort();
238 15947 : }
239 :
240 : /************************************************************************/
241 : /* CPLDebug() */
242 : /************************************************************************/
243 :
244 : /**
245 : * Display a debugging message.
246 : *
247 : * The category argument is used in conjunction with the CPL_DEBUG
248 : * environment variable to establish if the message should be displayed.
249 : * If the CPL_DEBUG environment variable is not set, no debug messages
250 : * are emitted (use CPLError(CE_Warning,...) to ensure messages are displayed).
251 : * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
252 : * debug messages are shown. Otherwise only messages whose category appears
253 : * somewhere within the CPL_DEBUG value are displayed (as determinted by
254 : * strstr()).
255 : *
256 : * Categories are usually an identifier for the subsystem producing the
257 : * error. For instance "GDAL" might be used for the GDAL core, and "TIFF"
258 : * for messages from the TIFF translator.
259 : *
260 : * @param pszCategory name of the debugging message category.
261 : * @param pszFormat printf() style format string for message to display.
262 : * Remaining arguments are assumed to be for format.
263 : */
264 :
265 65425 : void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
266 :
267 : {
268 65425 : CPLErrorContext *psCtx = CPLGetErrorContext();
269 : char *pszMessage;
270 : va_list args;
271 65425 : const char *pszDebug = CPLGetConfigOption("CPL_DEBUG",NULL);
272 :
273 : #define ERROR_MAX 25000
274 :
275 : /* -------------------------------------------------------------------- */
276 : /* Does this message pass our current criteria? */
277 : /* -------------------------------------------------------------------- */
278 65425 : if( pszDebug == NULL )
279 65425 : return;
280 :
281 0 : if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") )
282 : {
283 0 : size_t i, nLen = strlen(pszCategory);
284 :
285 0 : for( i = 0; pszDebug[i] != '\0'; i++ )
286 : {
287 0 : if( EQUALN(pszCategory,pszDebug+i,nLen) )
288 0 : break;
289 : }
290 :
291 0 : if( pszDebug[i] == '\0' )
292 0 : return;
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Allocate a block for the error. */
297 : /* -------------------------------------------------------------------- */
298 0 : pszMessage = (char *) VSIMalloc( ERROR_MAX );
299 0 : if( pszMessage == NULL )
300 0 : return;
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Dal -- always log a timestamp as the first part of the line */
304 : /* to ensure one is looking at what one should be looking at! */
305 : /* -------------------------------------------------------------------- */
306 :
307 0 : pszMessage[0] = '\0';
308 : #ifdef TIMESTAMP_DEBUG
309 0 : if( CPLGetConfigOption( "CPL_TIMESTAMP", NULL ) != NULL )
310 : {
311 0 : strcpy( pszMessage, VSICTime( VSITime(NULL) ) );
312 :
313 : // On windows anyway, ctime puts a \n at the end, but I'm not
314 : // convinced this is standard behaviour, so we'll get rid of it
315 : // carefully
316 :
317 0 : if (pszMessage[strlen(pszMessage) -1 ] == '\n')
318 : {
319 0 : pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
320 : }
321 0 : strcat( pszMessage, ": " );
322 : }
323 : #endif
324 :
325 : /* -------------------------------------------------------------------- */
326 : /* Add the category. */
327 : /* -------------------------------------------------------------------- */
328 0 : strcat( pszMessage, pszCategory );
329 0 : strcat( pszMessage, ": " );
330 :
331 : /* -------------------------------------------------------------------- */
332 : /* Format the application provided portion of the debug message. */
333 : /* -------------------------------------------------------------------- */
334 0 : va_start(args, pszFormat);
335 : #if defined(HAVE_VSNPRINTF)
336 : vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage),
337 0 : pszFormat, args);
338 : #else
339 : vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
340 : #endif
341 0 : va_end(args);
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Invoke the current error handler. */
345 : /* -------------------------------------------------------------------- */
346 0 : if( psCtx->psHandlerStack != NULL )
347 : {
348 0 : psCtx->psHandlerStack->pfnHandler( CE_Debug, CPLE_None, pszMessage );
349 : }
350 : else
351 : {
352 0 : CPLMutexHolderD( &hErrorMutex );
353 0 : if( pfnErrorHandler != NULL )
354 0 : pfnErrorHandler( CE_Debug, CPLE_None, pszMessage );
355 : }
356 :
357 0 : VSIFree( pszMessage );
358 : }
359 :
360 : /**********************************************************************
361 : * CPLErrorReset()
362 : **********************************************************************/
363 :
364 : /**
365 : * Erase any traces of previous errors.
366 : *
367 : * This is normally used to ensure that an error which has been recovered
368 : * from does not appear to be still in play with high level functions.
369 : */
370 :
371 367608 : void CPL_STDCALL CPLErrorReset()
372 : {
373 367608 : CPLErrorContext *psCtx = CPLGetErrorContext();
374 :
375 367608 : psCtx->nLastErrNo = CPLE_None;
376 367608 : psCtx->szLastErrMsg[0] = '\0';
377 367608 : psCtx->eLastErrType = CE_None;
378 367608 : }
379 :
380 :
381 : /**********************************************************************
382 : * CPLGetLastErrorNo()
383 : **********************************************************************/
384 :
385 : /**
386 : * Fetch the last error number.
387 : *
388 : * Fetches the last error number posted with CPLError(), that hasn't
389 : * been cleared by CPLErrorReset(). This is the error number, not the error class.
390 : *
391 : * @return the error number of the last error to occur, or CPLE_None (0)
392 : * if there are no posted errors.
393 : */
394 :
395 727589 : int CPL_STDCALL CPLGetLastErrorNo()
396 : {
397 727589 : CPLErrorContext *psCtx = CPLGetErrorContext();
398 :
399 727589 : return psCtx->nLastErrNo;
400 : }
401 :
402 : /**********************************************************************
403 : * CPLGetLastErrorType()
404 : **********************************************************************/
405 :
406 : /**
407 : * Fetch the last error type.
408 : *
409 : * Fetches the last error type posted with CPLError(), that hasn't
410 : * been cleared by CPLErrorReset(). This is the error class, not the error number.
411 : *
412 : * @return the error type of the last error to occur, or CE_None (0)
413 : * if there are no posted errors.
414 : */
415 :
416 339652 : CPLErr CPL_STDCALL CPLGetLastErrorType()
417 : {
418 339652 : CPLErrorContext *psCtx = CPLGetErrorContext();
419 :
420 339652 : return psCtx->eLastErrType;
421 : }
422 :
423 : /**********************************************************************
424 : * CPLGetLastErrorMsg()
425 : **********************************************************************/
426 :
427 : /**
428 : * Get the last error message.
429 : *
430 : * Fetches the last error message posted with CPLError(), that hasn't
431 : * been cleared by CPLErrorReset(). The returned pointer is to an internal
432 : * string that should not be altered or freed.
433 : *
434 : * @return the last error message, or NULL if there is no posted error
435 : * message.
436 : */
437 :
438 115 : const char* CPL_STDCALL CPLGetLastErrorMsg()
439 : {
440 115 : CPLErrorContext *psCtx = CPLGetErrorContext();
441 :
442 115 : return psCtx->szLastErrMsg;
443 : }
444 :
445 : /************************************************************************/
446 : /* CPLDefaultErrorHandler() */
447 : /************************************************************************/
448 :
449 : void CPL_STDCALL CPLDefaultErrorHandler( CPLErr eErrClass, int nError,
450 47 : const char * pszErrorMsg )
451 :
452 : {
453 : static int bLogInit = FALSE;
454 47 : static FILE * fpLog = stderr;
455 : static int nCount = 0;
456 : static int nMaxErrors = -1;
457 :
458 47 : if (eErrClass != CE_Debug)
459 : {
460 47 : if( nMaxErrors == -1 )
461 : {
462 : nMaxErrors =
463 4 : atoi(CPLGetConfigOption( "CPL_MAX_ERROR_REPORTS", "1000" ));
464 : }
465 :
466 47 : nCount++;
467 47 : if (nCount > nMaxErrors && nMaxErrors > 0 )
468 0 : return;
469 : }
470 :
471 47 : if( !bLogInit )
472 : {
473 4 : bLogInit = TRUE;
474 :
475 4 : fpLog = stderr;
476 4 : if( CPLGetConfigOption( "CPL_LOG", NULL ) != NULL )
477 : {
478 0 : fpLog = fopen( CPLGetConfigOption("CPL_LOG",""), "wt" );
479 0 : if( fpLog == NULL )
480 0 : fpLog = stderr;
481 : }
482 : }
483 :
484 47 : if( eErrClass == CE_Debug )
485 0 : fprintf( fpLog, "%s\n", pszErrorMsg );
486 47 : else if( eErrClass == CE_Warning )
487 30 : fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
488 : else
489 17 : fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
490 :
491 47 : if (eErrClass != CE_Debug
492 : && nMaxErrors > 0
493 : && nCount == nMaxErrors )
494 : {
495 : fprintf( fpLog,
496 : "More than %d errors or warnings have been reported. "
497 : "No more will be reported from now.\n",
498 0 : nMaxErrors );
499 : }
500 :
501 47 : fflush( fpLog );
502 : }
503 :
504 : /************************************************************************/
505 : /* CPLQuietErrorHandler() */
506 : /************************************************************************/
507 :
508 : void CPL_STDCALL CPLQuietErrorHandler( CPLErr eErrClass , int nError,
509 15900 : const char * pszErrorMsg )
510 :
511 : {
512 15900 : if( eErrClass == CE_Debug )
513 0 : CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg );
514 15900 : }
515 :
516 : /************************************************************************/
517 : /* CPLLoggingErrorHandler() */
518 : /************************************************************************/
519 :
520 : void CPL_STDCALL CPLLoggingErrorHandler( CPLErr eErrClass, int nError,
521 0 : const char * pszErrorMsg )
522 :
523 : {
524 : static int bLogInit = FALSE;
525 0 : static FILE * fpLog = stderr;
526 :
527 0 : if( !bLogInit )
528 : {
529 0 : const char *cpl_log = NULL;
530 :
531 0 : CPLSetConfigOption( "CPL_TIMESTAMP", "ON" );
532 :
533 0 : bLogInit = TRUE;
534 :
535 0 : cpl_log = CPLGetConfigOption("CPL_LOG", NULL );
536 :
537 0 : fpLog = stderr;
538 0 : if( cpl_log != NULL && EQUAL(cpl_log,"OFF") )
539 : {
540 0 : fpLog = NULL;
541 : }
542 0 : else if( cpl_log != NULL )
543 : {
544 : char* pszPath;
545 0 : int i = 0;
546 :
547 0 : pszPath = (char*)CPLMalloc(strlen(cpl_log) + 20);
548 0 : strcpy(pszPath, cpl_log);
549 :
550 0 : while( (fpLog = fopen( pszPath, "rt" )) != NULL )
551 : {
552 0 : fclose( fpLog );
553 :
554 : /* generate sequenced log file names, inserting # before ext.*/
555 0 : if (strrchr(cpl_log, '.') == NULL)
556 : {
557 : sprintf( pszPath, "%s_%d%s", cpl_log, i++,
558 0 : ".log" );
559 : }
560 : else
561 : {
562 0 : size_t pos = 0;
563 0 : char *cpl_log_base = strdup(cpl_log);
564 0 : pos = strcspn(cpl_log_base, ".");
565 0 : if (pos > 0)
566 : {
567 0 : cpl_log_base[pos] = '\0';
568 : }
569 : sprintf( pszPath, "%s_%d%s", cpl_log_base,
570 0 : i++, ".log" );
571 0 : free(cpl_log_base);
572 : }
573 : }
574 :
575 0 : fpLog = fopen( pszPath, "wt" );
576 0 : CPLFree(pszPath);
577 : }
578 : }
579 :
580 0 : if( fpLog == NULL )
581 0 : return;
582 :
583 0 : if( eErrClass == CE_Debug )
584 0 : fprintf( fpLog, "%s\n", pszErrorMsg );
585 0 : else if( eErrClass == CE_Warning )
586 0 : fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
587 : else
588 0 : fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
589 :
590 0 : fflush( fpLog );
591 : }
592 :
593 : /**********************************************************************
594 : * CPLTurnFailureIntoWarning() *
595 : **********************************************************************/
596 :
597 20 : void CPLTurnFailureIntoWarning(int bOn )
598 : {
599 20 : CPLErrorContext *psCtx = CPLGetErrorContext();
600 20 : psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
601 20 : if (psCtx->nFailureIntoWarning < 0)
602 : {
603 0 : CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / CPLTurnFailureIntoWarning(FALSE)");
604 : }
605 20 : }
606 :
607 : /**********************************************************************
608 : * CPLSetErrorHandler()
609 : **********************************************************************/
610 :
611 : /**
612 : * Install custom error handler.
613 : *
614 : * Allow the library's user to specify his own error handler function.
615 : * A valid error handler is a C function with the following prototype:
616 : *
617 : * <pre>
618 : * void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
619 : * </pre>
620 : *
621 : * Pass NULL to come back to the default behavior. The default behaviour
622 : * (CPLDefaultErrorHandler()) is to write the message to stderr.
623 : *
624 : * The msg will be a partially formatted error message not containing the
625 : * "ERROR %d:" portion emitted by the default handler. Message formatting
626 : * is handled by CPLError() before calling the handler. If the error
627 : * handler function is passed a CE_Fatal class error and returns, then
628 : * CPLError() will call abort(). Applications wanting to interrupt this
629 : * fatal behaviour will have to use longjmp(), or a C++ exception to
630 : * indirectly exit the function.
631 : *
632 : * Another standard error handler is CPLQuietErrorHandler() which doesn't
633 : * make any attempt to report the passed error or warning messages but
634 : * will process debug messages via CPLDefaultErrorHandler.
635 : *
636 : * Note that error handlers set with CPLSetErrorHandler() apply to all
637 : * threads in an application, while error handlers set with CPLPushErrorHandler
638 : * are thread-local. However, any error handlers pushed with
639 : * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
640 : * precidence over the global error handlers set with CPLSetErrorHandler().
641 : * Generally speaking CPLSetErrorHandler() would be used to set a desired
642 : * global error handler, while CPLPushErrorHandler() would be used to install
643 : * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
644 : * error reporting in a limited segment of code.
645 : *
646 : * @param pfnErrorHandlerNew new error handler function.
647 : * @return returns the previously installed error handler.
648 : */
649 :
650 : CPLErrorHandler CPL_STDCALL
651 0 : CPLSetErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
652 : {
653 0 : CPLErrorHandler pfnOldHandler = pfnErrorHandler;
654 0 : CPLErrorContext *psCtx = CPLGetErrorContext();
655 :
656 0 : if( psCtx->psHandlerStack != NULL )
657 : {
658 : CPLDebug( "CPL",
659 : "CPLSetErrorHandler() called with an error handler on\n"
660 0 : "the local stack. New error handler will not be used immediately.\n" );
661 : }
662 :
663 :
664 : {
665 0 : CPLMutexHolderD( &hErrorMutex );
666 :
667 0 : pfnOldHandler = pfnErrorHandler;
668 :
669 0 : if( pfnErrorHandler == NULL )
670 0 : pfnErrorHandler = CPLDefaultErrorHandler;
671 : else
672 0 : pfnErrorHandler = pfnErrorHandlerNew;
673 : }
674 :
675 0 : return pfnOldHandler;
676 : }
677 :
678 : /************************************************************************/
679 : /* CPLPushErrorHandler() */
680 : /************************************************************************/
681 :
682 : /**
683 : * Push a new CPLError handler.
684 : *
685 : * This pushes a new error handler on the thread-local error handler
686 : * stack. This handler will be used untill removed with CPLPopErrorHandler().
687 : *
688 : * The CPLSetErrorHandler() docs have further information on how
689 : * CPLError handlers work.
690 : *
691 : * @param pfnErrorHandlerNew new error handler function.
692 : */
693 :
694 15653 : void CPL_STDCALL CPLPushErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
695 :
696 : {
697 15653 : CPLErrorContext *psCtx = CPLGetErrorContext();
698 : CPLErrorHandlerNode *psNode;
699 :
700 15653 : psNode = (CPLErrorHandlerNode *) VSIMalloc(sizeof(CPLErrorHandlerNode));
701 15653 : psNode->psNext = psCtx->psHandlerStack;
702 15653 : psNode->pfnHandler = pfnErrorHandlerNew;
703 :
704 15653 : psCtx->psHandlerStack = psNode;
705 15653 : }
706 :
707 : /************************************************************************/
708 : /* CPLPopErrorHandler() */
709 : /************************************************************************/
710 :
711 : /**
712 : * Pop error handler off stack.
713 : *
714 : * Discards the current error handler on the error handler stack, and restores
715 : * the one in use before the last CPLPushErrorHandler() call. This method
716 : * has no effect if there are no error handlers on the current threads error
717 : * handler stack.
718 : */
719 :
720 15646 : void CPL_STDCALL CPLPopErrorHandler()
721 :
722 : {
723 15646 : CPLErrorContext *psCtx = CPLGetErrorContext();
724 :
725 15646 : if( psCtx->psHandlerStack != NULL )
726 : {
727 15646 : CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
728 :
729 15646 : psCtx->psHandlerStack = psNode->psNext;
730 15646 : VSIFree( psNode );
731 : }
732 15646 : }
733 :
734 : /************************************************************************/
735 : /* _CPLAssert() */
736 : /* */
737 : /* This function is called only when an assertion fails. */
738 : /************************************************************************/
739 :
740 : /**
741 : * Report failure of a logical assertion.
742 : *
743 : * Applications would normally use the CPLAssert() macro which expands
744 : * into code calling _CPLAssert() only if the condition fails. _CPLAssert()
745 : * will generate a CE_Fatal error call to CPLError(), indicating the file
746 : * name, and line number of the failed assertion, as well as containing
747 : * the assertion itself.
748 : *
749 : * There is no reason for application code to call _CPLAssert() directly.
750 : */
751 :
752 : void CPL_STDCALL _CPLAssert( const char * pszExpression, const char * pszFile,
753 0 : int iLine )
754 :
755 : {
756 : CPLError( CE_Fatal, CPLE_AssertionFailed,
757 : "Assertion `%s' failed\n"
758 : "in file `%s', line %d\n",
759 0 : pszExpression, pszFile, iLine );
760 0 : }
761 :
|