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