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