iError Project Site at SourceForge.net Logo
Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

iError.cpp

Go to the documentation of this file.
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 //#include <iostream>
00018 #ifdef WIN32
00019 //      #include <strstream>
00020         #include <windows.h>
00021 //      #include <iomanip>
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                 // initialize description parameters
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         } // if (m_ErrorCode)
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                         } // switch error level
00409                 } // if(m_Last)
00410         } // if(GetErrorLevel >= m_NotificationLevel)
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];  // format spec
00444                 char temp[ERR_MAX_DESCRIPTION];   // temporare output buffer
00445                 const char *i = m_ErrorCode->GetDescription();
00446                 if (i)
00447                 {
00448                         char *fp; // format pointer
00449                         int j=0;  // m_Param counter
00450                         while (i[0])
00451                         {
00452                                 if (i[0]=='%')
00453                                 {
00454                                         fp=format; // set fp to beginning of 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                         } // while i[0]
00527                 } else // no description
00528                 {
00529                         strcpy(m_Description, "unknown error");
00530                 }
00531         } else // m_errorHandler==NULL
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                 // ERR_MAX_STACK_DEPTH exceeded
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         // build m_Sig
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 }; // namespace iERR
00694 

© 2002 by C-LAB
generated by doxygen