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