00001 #include "iError.h"
00002 #include "iError-config.h"
00003
00004 #ifdef _POSIX_C_SOURCE
00005 # include <pthread.h>
00006 #endif
00007
00008 #ifdef USE_SPROC
00009 # include <sys/types.h>
00010 # include <sys/prctl.h>
00011 # include <unistd.h>
00012 # include <map>
00013 #endif
00014
00015 #include <cstdio>
00016
00017
00018 #ifdef WIN32
00019
00020 #include <windows.h>
00021
00022 #else
00023 # include <cstdio>
00024 # include <iostream>
00025 #endif
00026
00027 namespace iERR {
00028 #ifdef _POSIX_C_SOURCE
00029 using std::cerr;
00030 #endif
00031 #ifdef USE_SPROC
00032 using std::map;
00033 #endif
00034
00035 iErrorCode UNKNOWN("[UNKNOWN] Unknown Error");
00036 iErrorCode GENERIC("[GENERIC] %s");
00037 iErrorCode INTERNAL("[INTERNAL] Internal Error.");
00038 iErrorCode SYSTEM("[SYSTEM] System Error: %s");
00039 iErrorCode iERR_ASSERT("Assertion \"%s\" failed");
00040 iErrorCode iERR_NO_EXCEPTIONS("C++ exceptions are not supported by the current configuration");
00041
00044 iStdErrorHandler iStdErrorHandler::m_Default;
00045
00046 int iErrorHandler::m_HandlerCount=0;
00047
00048 #ifdef _POSIX_C_SOURCE
00049 static pthread_key_t g_Current;
00050 #endif
00051
00052 #ifdef USE_SPROC
00053 static iErrorHandler::CurrentTable_t g_Current;
00054 #endif
00055
00056 #ifdef WIN32
00057 static long g_Current;
00058 #endif
00059
00062 iErrorHandler::iErrorHandler()
00063 :m_Last(NULL)
00064 {
00065 m_LastError = new iError();
00066 if (m_HandlerCount==0)
00067 {
00068 #ifdef _POSIX_C_SOURCE
00069 int res = pthread_key_create(&g_Current, NULL);
00070 if(res) cerr << "error creating thread key: " << strerror(res) << endl;
00071 #endif
00072
00073 #ifdef WIN32
00074 if ((g_Current = TlsAlloc())== -1) MessageBox(NULL, _T("internal error: cannot create g_Current"), _T("FATAL"), MB_OK | MB_ICONSTOP);
00075 #endif
00076 }
00077 m_HandlerCount++;
00078 }
00079
00081 iErrorHandler::~iErrorHandler()
00082 {
00083 delete m_LastError;
00084 m_HandlerCount--;
00085 if (m_HandlerCount==0)
00086 {
00087 #ifdef _POSIX_C_SOURCE
00088 pthread_key_delete(g_Current);
00089 #endif
00090
00091 #ifdef WIN32
00092 TlsFree(g_Current);
00093 #endif
00094 }
00095 }
00096
00098 int
00099 iErrorHandler::Throw(
00100 iError::ErrorLevel errLevel,
00101 const char *functionName,
00102 const char *fileName,
00103 int lineNr,
00104 iErrorCode *errCode,
00105 ...
00106 )
00107 {
00108 m_LastError->SetErrorCode(errLevel, errCode);
00109 if (fileName)
00110 {
00111 m_LastError->AddDebugInfo
00112 (
00113 functionName,
00114 fileName,
00115 lineNr
00116 );
00117 }
00118
00119 if (errCode)
00120 {
00121
00122 va_list vp;
00123 va_start(vp, errCode);
00124 int i = 0;
00125 const char *c = errCode->GetSig();
00126 while(c[0])
00127 {
00128 switch(c[0])
00129 {
00130 case 'C':
00131 case 'c':
00132 case 'd':
00133 case 'i':
00134 case 'o':
00135 case 'u':
00136 case 'x':
00137 case 'X':
00138 m_LastError->SetIntegerParam(i, va_arg(vp, int));
00139 break;
00140 case 'e':
00141 case 'E':
00142 case 'f':
00143 case 'g':
00144 case 'G':
00145 m_LastError->SetDoubleParam(i, va_arg(vp, double));
00146 break;
00147 case 'S':
00148 case 's':
00149 m_LastError->SetStringParam(i, va_arg(vp, char*));
00150 break;
00151 case 'p':
00152 case 'n':
00153 m_LastError->SetVoidParam(i, va_arg(vp, void*));
00154 break;
00155 }
00156 i++;
00157 c++;
00158 }
00159 va_end(vp);
00160 }
00161
00162 m_Last=m_LastError;
00163 _Throw();
00164 return (errCode ? errCode->GetErrorCode() : 0);
00165 }
00166
00168 bool
00169 iErrorHandler::Rethrow(
00170 const char *functionName,
00171 const char *file,
00172 int line
00173 )
00174 {
00175 bool result = false;
00176 if (m_Last)
00177 {
00178 if (file)
00179 {
00180 m_Last->AddDebugInfo(
00181 functionName,
00182 file,
00183 line
00184 );
00185 }
00186 _Throw();
00187 result = true;
00188 }
00189 return result;
00190 }
00191
00193 bool
00194 iErrorHandler::Handle(
00195 const char *functionName,
00196 const char *file,
00197 int line
00198 )
00199 {
00200 bool result = false;
00201 if (m_Last)
00202 {
00203 if (file)
00204 {
00205 m_Last->AddDebugInfo(
00206 functionName,
00207 file,
00208 line
00209 );
00210 }
00211 _Handle();
00212 m_Last=NULL;
00213 result=true;
00214 }
00215 return result;
00216 }
00217
00219 bool
00220 iErrorHandler::Reset()
00221 {
00222 bool result = false;
00223 if (m_Last)
00224 {
00225 m_Last=NULL;
00226 result=true;
00227 }
00228 return result;
00229 }
00230
00232 iError*
00233 iErrorHandler::LastError(bool reset)
00234 {
00235 iError* result = m_Last;
00236 if (reset) Reset();
00237 return result;
00238 }
00239
00241 iErrorHandler*
00242 iErrorHandler::Current()
00243 {
00244 #ifdef _POSIX_C_SOURCE
00245 iErrorHandler* res = (iErrorHandler*)pthread_getspecific(g_Current);
00246 if (!res)
00247 {
00248 res = &iStdErrorHandler::m_Default;
00249 pthread_setspecific(g_Current,res);
00250 }
00251 return res;
00252 #endif
00253
00254 #ifdef USE_SPROC
00255 iErrorHandler* res = &iStdErrorHandler::m_Default;
00256 CurrentTable_t::iterator item = g_Current.find(getpid());
00257 if (item != g_Current.end())
00258 {
00259 res = (*item).second;
00260 }
00261 return res;
00262 #endif
00263
00264 #ifdef WIN32
00265 iErrorHandler* res = (iErrorHandler*)TlsGetValue(g_Current);
00266 if (!res)
00267 {
00268 res = &iStdErrorHandler::m_Default;
00269 TlsSetValue(g_Current,res);
00270 }
00271 return res;
00272 #endif
00273 }
00274
00276 iErrorHandler*
00277 iErrorHandler::SetCurrent()
00278 {
00279 #ifdef _POSIX_C_SOURCE
00280 iErrorHandler *result = (iErrorHandler*)pthread_getspecific(g_Current);
00281 pthread_setspecific(g_Current,this);
00282 #endif
00283
00284 #ifdef USE_SPROC
00285 pid_t threadID = getpid();
00286 iErrorHandler* result = &iStdErrorHandler::m_Default;
00287 CurrentTable_t::iterator item = g_Current.find(threadID);
00288 if (item != g_Current.end())
00289 {
00290 result = (*item).second;
00291 }
00292 g_Current[threadID]=this;
00293 #endif
00294
00295 #ifdef WIN32
00296 iErrorHandler *result = (iErrorHandler*)TlsGetValue(g_Current);
00297 TlsSetValue(g_Current,this);
00298 #endif
00299
00300 return result;
00301 }
00302
00305 iStdErrorHandler::iStdErrorHandler()
00306 :m_NotificationLevel(iError::iINFO)
00307 #ifdef _DEBUG
00308 ,m_ShowDebugInfo(true)
00309 #else
00310 ,m_ShowDebugInfo(false)
00311 #endif
00312 {
00313 }
00314
00315 void
00316 iStdErrorHandler::_Throw()
00317 {
00318 switch (m_Last->GetErrorLevel())
00319 {
00320 case iError::iINFO:
00321 case iError::iWARNING:
00322 Handle();
00323 break;
00324 case iError::iCRITICAL:
00325 break;
00326 case iError::iEXCEPTION:
00327 #ifdef HAVE_EXCEPTIONS
00328 throw LastError();
00329 #else
00330 iThrow(WARNING(iERR_NO_EXCEPTIONS));
00331 break;
00332 #endif
00333 case iError::iASSERTION:
00334 Handle();
00335 exit(-1);
00336 default:
00337 iThrow(WARNING(UNKNOWN));
00338 }
00339 }
00340
00342 void
00343 iStdErrorHandler::_Handle()
00344 {
00345 if (m_Last->GetErrorLevel()>=m_NotificationLevel)
00346 {
00347 char buf[2001];
00348 # ifdef WIN32
00349 int _i;
00350 TCHAR buff[2001];
00351 # endif
00352 if (m_Last)
00353 {
00354 if (m_ShowDebugInfo)
00355 {
00356 sprintf(buf, "%s\nDebug info:\n%s", m_Last->GetDescription(), m_Last->GetDebugInfo());
00357 } else
00358 {
00359 sprintf(buf, "%s", m_Last->GetDescription());
00360 }
00361 # ifdef WIN32
00362 for (_i=0; buf[_i]!=0; ++_i) {buff[_i]=(TCHAR)buf[_i]; }; buff[_i]=0;
00363 # endif
00364 switch(m_Last->GetErrorLevel())
00365 {
00366 case iError::iINFO:
00367 # ifdef WIN32
00368 MessageBox(NULL, buff, _T("INFO"), MB_OK | MB_ICONINFORMATION);
00369 # else
00370 cerr << "INFO: " << buf << endl;
00371 # endif
00372 break;
00373 case iError::iWARNING:
00374 # ifdef WIN32
00375 MessageBox(NULL, buff, _T("WARNING"), MB_OK | MB_ICONEXCLAMATION);
00376 # else
00377 cerr << "WARNING: " << buf << endl;
00378 # endif
00379 break;
00380 case iError::iCRITICAL:
00381 # ifdef WIN32
00382 MessageBox(NULL, buff, _T("CRITICAL"), MB_OK | MB_ICONSTOP);
00383 # else
00384 cerr << "CRITICAL: " << buf << endl;
00385 # endif
00386 break;
00387 case iError::iEXCEPTION:
00388 # ifdef WIN32
00389 MessageBox(NULL, buff, _T("EXCEPTION"), MB_OK | MB_ICONSTOP);
00390 # else
00391 cerr << "EXCEPTION: " << buf << endl;
00392 # endif
00393 break;
00394 case iError::iASSERTION:
00395 # ifdef WIN32
00396 MessageBox(NULL, buff, _T("assertion failed"), MB_OK | MB_ICONSTOP);
00397 # else
00398 cerr << buf << endl;
00399 # endif
00400 break;
00401 default:
00402 # ifdef WIN32
00403 MessageBox(NULL, buff, _T("iError"), MB_OK | MB_ICONSTOP);
00404 # else
00405 cerr << "iError: " << buf << endl;
00406 # endif
00407 break;
00408 }
00409 }
00410 }
00411 }
00412
00415 iError::iError()
00416 :m_ErrorLevel(iINFO)
00417 ,m_ErrorCode(&UNKNOWN)
00418 ,m_LastDebugInfo(0)
00419 {
00420 }
00421
00423 iError::ErrorLevel
00424 iError::GetErrorLevel() const
00425 {
00426 return m_ErrorLevel;
00427 }
00428
00430 iErrorCode*
00431 iError::GetErrorCode() const
00432 {
00433 return m_ErrorCode;
00434 }
00435
00437 const char*
00438 iError::GetDescription()
00439 {
00440 m_Description[0]='\0';
00441 if (m_ErrorCode)
00442 {
00443 char format[30];
00444 char temp[ERR_MAX_DESCRIPTION];
00445 const char *i = m_ErrorCode->GetDescription();
00446 if (i)
00447 {
00448 char *fp;
00449 int j=0;
00450 while (i[0])
00451 {
00452 if (i[0]=='%')
00453 {
00454 fp=format;
00455 fp[0]='%';
00456 fp++;
00457 i++;
00458 bool found = true;
00459 while (found)
00460 {
00461 switch(i[0])
00462 {
00463 case 'C':
00464 case 'c':
00465 case 'd':
00466 case 'i':
00467 case 'o':
00468 case 'u':
00469 case 'x':
00470 case 'X':
00471 fp[0]=i[0];
00472 fp[1]='\0';
00473 sprintf(temp, format, m_Param[j].GetInt());
00474 j++;
00475 strcat(m_Description, temp);
00476 found=false;
00477 break;
00478
00479 case 'e':
00480 case 'E':
00481 case 'f':
00482 case 'g':
00483 case 'G':
00484 fp[0]=i[0];
00485 fp[1]='\0';
00486 sprintf(temp, format, m_Param[j].GetDouble());
00487 j++;
00488 strcat(m_Description, temp);
00489 found=false;
00490 break;
00491
00492 case 'S':
00493 case 's':
00494 fp[0]=i[0];
00495 fp[1]='\0';
00496 sprintf(temp, format, m_Param[j].GetString());
00497 j++;
00498 strcat(m_Description, temp);
00499 found=false;
00500 break;
00501 case 'p':
00502 case 'n':
00503 fp[0]=i[0];
00504 fp[1]='\0';
00505 sprintf(temp, format, m_Param[j].GetVoid());
00506 j++;
00507 strcat(m_Description, temp);
00508 found=false;
00509 break;
00510
00511 case '%':
00512 strcat(m_Description, "%");
00513 found=false;
00514 break;
00515
00516 default:
00517 fp[0]=i[0];
00518 fp++;
00519 i++;
00520 }
00521 }
00522 } else {
00523 strncat(m_Description, &i[0], 1);
00524 }
00525 i++;
00526 }
00527 } else
00528 {
00529 strcpy(m_Description, "unknown error");
00530 }
00531 } else
00532 {
00533 strcpy(m_Description, "unknown error");
00534 }
00535 return m_Description;
00536 }
00537
00539 const char*
00540 iError::GetDebugInfo()
00541 {
00542 char temp[ERR_MAX_DEBUG_DESCRIPTION];
00543 m_DebugInfo[0]='\0';
00544 for (int i=0; i<m_LastDebugInfo; ++i)
00545 {
00546 sprintf(temp, "\t%s (%s in line %d)", m_Function[i], m_File[i], m_Line[i]);
00547 if (i>0)
00548 {
00549 strcat(m_DebugInfo, "\n");
00550 }
00551 strcat(m_DebugInfo, temp);
00552 }
00553 return m_DebugInfo;
00554 }
00555
00557 iError::operator long() const
00558 {
00559 if (m_ErrorCode)
00560 {
00561 return m_ErrorCode->GetErrorCode();
00562 } else
00563 {
00564 return 0;
00565 }
00566 }
00567
00569 void
00570 iError::SetErrorCode(ErrorLevel errLevel, iErrorCode* errCode)
00571 {
00572 m_ErrorLevel = errLevel;
00573 m_ErrorCode = errCode;
00574 m_LastDebugInfo = 0;
00575 }
00576
00578 void
00579 iError::SetIntegerParam(int idx, int value)
00580 {
00581 m_Param[idx].SetInt(value);
00582 }
00583
00585 void
00586 iError::SetDoubleParam(int idx, double value)
00587 {
00588 m_Param[idx].SetDouble(value);
00589 }
00590
00592 void
00593 iError::SetStringParam(int idx, const char* value)
00594 {
00595 m_Param[idx].SetString(value);
00596 }
00597
00599 void
00600 iError::SetVoidParam(int idx, void* value)
00601 {
00602 m_Param[idx].SetVoid(value);
00603 }
00604
00606 void
00607 iError::AddDebugInfo(
00608 const char* functionName,
00609 const char* fileName,
00610 int lineNr
00611 )
00612 {
00613 if (m_LastDebugInfo<ERR_MAX_STACK_DEPTH)
00614 {
00615 m_File[m_LastDebugInfo] = fileName;
00616 m_Line[m_LastDebugInfo] = lineNr;
00617 m_Function[m_LastDebugInfo] = functionName;
00618 ++m_LastDebugInfo;
00619 } else
00620 {
00621
00622 }
00623 }
00624
00627 iErrorCode::iErrorCode(
00628 const char *description,
00629 int errCode
00630 )
00631 :m_Description(description)
00632 ,m_ErrorCode(errCode)
00633 {
00634 if (!m_Description) m_Description="unspecified error";
00635
00636 int j=0;
00637 bool found=true;
00638 const char *i = m_Description;
00639 while (i[0] && j<ERR_MAX_PARAM)
00640 {
00641 if (i[0]=='%')
00642 {
00643 i++;
00644 found=true;
00645 while (found)
00646 {
00647 switch(i[0])
00648 {
00649 case 'c':
00650 case 'C':
00651 case 'd':
00652 case 'i':
00653 case 'o':
00654 case 'u':
00655 case 'x':
00656 case 'X':
00657 case 'e':
00658 case 'E':
00659 case 'f':
00660 case 'g':
00661 case 'G':
00662 case 's':
00663 case 'S':
00664 case 'p':
00665 case 'n':
00666 m_Sig[j]=i[0]; j++;
00667 found=false;
00668 break;
00669
00670 case '%':
00671 found=false;
00672 break;
00673
00674 case '\0':
00675 found=false;
00676 break;
00677
00678 default:
00679 i++;
00680 }
00681 }
00682 }
00683 i++;
00684 }
00685 m_Sig[j]='\0';
00686 }
00687
00689 iErrorCode::~iErrorCode()
00690 {
00691 }
00692
00693 };
00694