exception.cpp

Go to the documentation of this file.
00001 
00015 #include <cstdarg>
00016 #include <cstdio>
00017 #include <cstring>
00018 #include <stdexcept>
00019 #include <dlrCommon/exception.h>
00020 
00021 // Anonymous namespace for local functions.
00022 namespace {
00023 
00024   // std::snprintf() doesn't seem to be supported on some
00025   // architectures, so we define a crippled version here which fills
00026   // our needs.
00027   int l_snprintf(char* targetPtr, size_t targetSize, 
00028                  const char* formatPtr, ...) {
00029     char workingBuffer[1024];
00030     va_list varArgsList;
00031     va_start(varArgsList, formatPtr);
00032 
00033     const char* workingFormatPtr = formatPtr;
00034     char* workingTargetPtr = targetPtr;
00035     size_t spaceLeft = targetSize - 1;
00036 
00037     // Stop if we've used up either the available space or the format string.
00038     while(spaceLeft && (*workingFormatPtr != '\0')) {
00039       int intValue;
00040       double doubleValue;
00041       char* charPtrValue;
00042       size_t stringSize;
00043       if(*workingFormatPtr == '%') {
00044         ++workingFormatPtr;
00045         switch(*workingFormatPtr) {
00046         case '\0':
00047           break;
00048         case 'd':
00049           intValue = va_arg(varArgsList, int);
00050           sprintf(workingBuffer, "%d", intValue);
00051           std::strncpy(workingTargetPtr, workingBuffer, spaceLeft);
00052           stringSize = strlen(workingBuffer);
00053           workingTargetPtr +=
00054             (stringSize > spaceLeft) ? spaceLeft : stringSize;
00055           spaceLeft -= (stringSize > spaceLeft) ? spaceLeft : stringSize;
00056           ++workingFormatPtr;
00057           break;
00058         case 'f':
00059           doubleValue = va_arg(varArgsList, double);
00060           sprintf(workingBuffer, "%f", doubleValue);
00061           std::strncpy(workingTargetPtr, workingBuffer, spaceLeft);
00062           stringSize = strlen(workingBuffer);
00063           workingTargetPtr +=
00064             (stringSize > spaceLeft) ? spaceLeft : stringSize;
00065           spaceLeft -= (stringSize > spaceLeft) ? spaceLeft : stringSize;
00066           ++workingFormatPtr;
00067           break;
00068         case 's':
00069           charPtrValue = va_arg(varArgsList, char*);
00070           std::strncpy(workingTargetPtr, charPtrValue, spaceLeft);
00071           stringSize = strlen(charPtrValue);
00072           workingTargetPtr +=
00073             (stringSize > spaceLeft) ? spaceLeft : stringSize;
00074           spaceLeft -= (stringSize > spaceLeft) ? spaceLeft : stringSize;
00075           ++workingFormatPtr;
00076           break;
00077         default:
00078           va_end(varArgsList);
00079           std::sprintf(
00080             workingBuffer,
00081             "Exception(l_snprintf()): Format string %%%c not recognized.",
00082             *workingFormatPtr);
00083           throw std::invalid_argument(workingBuffer);
00084         }
00085       } else {
00086         *workingTargetPtr++ = *workingFormatPtr++;
00087         --spaceLeft;
00088       }
00089     }
00090     if(targetSize > 0) {
00091       *workingTargetPtr = '\0';
00092     }
00093     va_end(varArgsList);
00094     return static_cast<int>(workingTargetPtr - targetPtr);
00095   }
00096 
00097 } // Anonymous namespace.
00098 
00099 
00100 namespace dlr {
00101 
00102   namespace common {
00103 
00104     // This constructor sets the internal "what()" message.  The
00105     Exception::
00106     Exception(const char* message)
00107       throw()
00108       : std::exception(),
00109         m_traceMessage(),
00110         m_traceMessageIndex(0)
00111     {
00112       l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH, "Exception: %s",
00113                  message);
00114       m_traceMessage[0] = '\0';
00115     }
00116 
00117 
00118     // Constructor which accepts a few more details.
00119     Exception::
00120     Exception(const char* message, const char* fileName, int lineNumber)
00121       throw()
00122       : std::exception(),
00123         m_traceMessage(),
00124         m_traceMessageIndex(0)
00125     {
00126       l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH,
00127                  "Exception(%s, %d): %s",
00128                  fileName, lineNumber, message);
00129       m_traceMessage[0] = '\0';
00130     }
00131 
00132 
00133     // Constructor which accepts a even more details.
00134     Exception::
00135     Exception(const char* message, const char* functionName,
00136               const char* fileName, int lineNumber)
00137       throw()
00138       : std::exception(),
00139         m_traceMessage(),
00140         m_traceMessageIndex(0)
00141     {
00142       l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH,
00143                  "Exception(%s, %s, %d): %s",
00144                  functionName, fileName, lineNumber, message);
00145       m_traceMessage[0] = '\0';
00146     }
00147 
00148 
00149     // Copy constructor.
00150     Exception::
00151     Exception(const Exception& source)
00152       throw()
00153       : std::exception(),
00154         m_traceMessage(),
00155         m_traceMessageIndex(source.m_traceMessageIndex)
00156     {
00157       strncpy(m_message, source.m_message, DLR_EXCEPTION_MESSAGE_LENGTH);
00158       m_message[DLR_EXCEPTION_MESSAGE_LENGTH - 1] = '\0';
00159 
00160       size_t traceMessageMaxLength =
00161         (DLR_EXCEPTION_TRACE_REQUIRED_STACK_LEVELS
00162          * DLR_EXCEPTION_TRACE_MESSAGE_LENGTH);
00163       strncpy(m_traceMessage, source.m_traceMessage, traceMessageMaxLength);
00164       m_traceMessage[traceMessageMaxLength - 1] = '\0';
00165     }
00166 
00167 
00168     // Assignment operator.
00169     Exception& Exception::
00170     operator=(const Exception& source)
00171       throw()
00172     {
00173       strncpy(m_message, source.m_message, DLR_EXCEPTION_MESSAGE_LENGTH);
00174       m_message[DLR_EXCEPTION_MESSAGE_LENGTH - 1] = '\0';
00175 
00176       size_t traceMessageMaxLength =
00177         (DLR_EXCEPTION_TRACE_REQUIRED_STACK_LEVELS
00178          * DLR_EXCEPTION_TRACE_MESSAGE_LENGTH);
00179       strncpy(m_traceMessage, source.m_traceMessage, traceMessageMaxLength);
00180       m_traceMessage[traceMessageMaxLength - 1] = '\0';
00181 
00182       m_traceMessageIndex = source.m_traceMessageIndex;
00183     
00184       return *this;
00185     }
00186 
00187 
00188     // Protected constructor.
00189     Exception::
00190     Exception(const char* message, const char* childClassName)
00191       throw()
00192       : std::exception(),
00193         m_traceMessage(),
00194         m_traceMessageIndex(0)
00195     {
00196       l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH, "%s: %s",
00197                  childClassName, message);
00198       m_traceMessage[0] = '\0';
00199     }
00200 
00201 
00202     // Protected constructor.
00203     Exception::
00204     Exception(const char* message, const char* childClassName,
00205               const char* functionName, const char* fileName,
00206               int lineNumber)
00207       throw()
00208       : std::exception(),
00209         m_traceMessage(),
00210         m_traceMessageIndex(0)
00211     {
00212       if(functionName == 0) {
00213         l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH,
00214                    "%s(%s, %d): %s",
00215                    childClassName, fileName, lineNumber, message);
00216       } else {
00217         l_snprintf(m_message, DLR_EXCEPTION_MESSAGE_LENGTH,
00218                    "%s(%s, %s, %d): %s",
00219                    childClassName, functionName, fileName, lineNumber,
00220                    message);
00221       }
00222       m_traceMessage[0] = '\0';
00223     }
00224 
00225 
00226     // This public method appends the provided text to the internal
00227     // "trace()" message.
00228     void
00229     Exception::
00230     addTrace(const char* message)
00231       throw()
00232     {
00233       const char* ellipsisString = "...";
00234       size_t ellipsisLength = strlen(ellipsisString);
00235 
00236       // Sanity check.
00237       if(DLR_EXCEPTION_TRACE_MESSAGE_LENGTH < (ellipsisLength + 1)) {
00238         return;
00239       }
00240     
00241       if(message != 0) {
00242         // This flag tells us whether we've truncated the string.
00243         bool useEllipsis = false;
00244       
00245         // strlen does not count the terminator.
00246         size_t messageLength = std::strlen(message); 
00247         if(messageLength >= DLR_EXCEPTION_TRACE_MESSAGE_LENGTH) {
00248           messageLength = DLR_EXCEPTION_TRACE_MESSAGE_LENGTH - 1;
00249           useEllipsis = true;
00250         }
00251 
00252         // If the trace message is filled up, we stop recording.
00253         size_t remainingSpace =
00254           (DLR_EXCEPTION_TRACE_REQUIRED_STACK_LEVELS
00255            * DLR_EXCEPTION_TRACE_MESSAGE_LENGTH) - m_traceMessageIndex;
00256         if((messageLength + 1) > remainingSpace) {
00257           // Forbid future trace information as well by pretending
00258           // there's no space left at all.
00259           m_traceMessageIndex = (DLR_EXCEPTION_TRACE_REQUIRED_STACK_LEVELS
00260                                  * DLR_EXCEPTION_TRACE_MESSAGE_LENGTH);
00261           return;
00262         }
00263 
00264         // If we're going to append a "...", better make sure there's
00265         // room for it.
00266         if(useEllipsis) {
00267           // Sanity check.  This should never be true.
00268           if(messageLength < ellipsisLength) {
00269             return;
00270           }
00271           messageLength -= ellipsisLength;
00272         }
00273 
00274         // The messageLength parameter will prevent this from copying
00275         // the final terminator.
00276         std::strncpy(
00277           m_traceMessage + m_traceMessageIndex, message, messageLength);
00278         m_traceMessageIndex += messageLength;
00279 
00280         // In both of the cases below, we don't advance
00281         // m_traceMessageIndex past the final '\0'.  This is because we
00282         // want to overwrite the terminator next time we get a message.
00283         if(useEllipsis) {
00284           // This copies the terminator as well.  
00285           std::strcpy(m_traceMessage + m_traceMessageIndex, ellipsisString);
00286           m_traceMessageIndex += strlen(ellipsisString);
00287         } else {
00288           m_traceMessage[m_traceMessageIndex] = '\0';
00289         }
00290       }
00291     }
00292 
00293   } // namespace common
00294   
00295 } // namespace dlr

Generated on Mon Jul 9 20:34:02 2007 for dlrLibs Utility Libraries by  doxygen 1.5.2