exception.cpp

00001 
00002 /***************************************************************************
00003  *  exception.cpp - basic exception
00004  *
00005  *  Generated: Thu Feb 09 13:04:45 2006 (from FireVision)
00006  *  Copyright  2005-2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <core/exception.h>
00025 #include <core/threading/mutex.h>
00026 
00027 #ifndef _GNU_SOURCE
00028 #define _GNU_SOURCE
00029 #endif
00030 
00031 #include <cstring>
00032 #include <cstdlib>
00033 #include <cstdio>
00034 #ifdef HAVE_EXECINFO
00035 #  include <execinfo.h>
00036 #endif
00037 
00038 namespace fawkes {
00039 
00040 /** @class Exception core/exception.h
00041  * Base class for exceptions in Fawkes.
00042  * Exceptions are a good way to handle errors. If you choose to use
00043  * exceptions use derivates of this class so that there is a unified way of
00044  * handling errors in Fawkes. Do <i>not</i> throw an arbitrary class such as
00045  * a string or integer as this is hard to handle.
00046  *
00047  * For your exceptions in general you only need to override the constructor
00048  * and call the Exception constructor with the appropriate message. In
00049  * cases where more information is needed about the error add appropriate
00050  * handlers.
00051  *
00052  * In most cases it is bad to just throw an Exception like this:
00053  *
00054  * @code
00055  * if ( error_condition ) {
00056  *   throw Exception("Out of memory");
00057  * }
00058  * @endcode
00059  *
00060  * Rather you should explicitly subclass Exception appropriately. For the
00061  * above example you could have something like this as exception class:
00062  *
00063  * @code
00064  * class OutOfMemException : public Exception
00065  * {
00066  *  public:
00067  *   OutOfMemoryException() : Exception("Out of memory") {}
00068  * }
00069  * @endcode
00070  *
00071  * And in your handling code you throw a OutOfMemoryException. This is
00072  * especially useful if it is possible to throw several different exceptions.
00073  * If the message was different you would have to parse the string for
00074  * the exact error. This can be avoided if you just catch different
00075  * exceptions. This is also useful if the Exception is not catched explicitly
00076  * as this will printout the name of the exception class thrown just before
00077  * exiting the program. And reading something like
00078  * "terminate called after throwing an instance of 'OutOfMemoryException'"
00079  * makes it a lot easier to spot the problem.
00080  *
00081  * Exceptions should be catched by reference like this:
00082  * @code
00083  * try {
00084  *   some_operation();
00085  * } catch (OutOfMemoryException &e) {
00086  *   std::cout << e.c_str() << std::endl;
00087  *   error_handling();
00088  * }
00089  * @endcode
00090  *
00091  * Messages are stored as list. The first message however is called the
00092  * primary message and it should contain as much information as available.
00093  * This message is printed on the screen if the application crashes with an
00094  * unhandled exception. So having meaningful content here means that the
00095  * error can be traced more easily.
00096  *
00097  * You can utilize the list feature by adding appropriate information
00098  * through appropriate try/catch statements. This way you can
00099  * build information path ways that will help to debug your software. Use
00100  * block like this to append information:
00101  * @code
00102  * try {
00103  *   potentially_failing();
00104  * } catch {MyException &e) {
00105  *   e.append("info where exception happened");
00106  *   throw; // re-throw exception
00107  * }
00108  * @endcode
00109  * This is especially useful if the exception may occur at several different
00110  * places and it cannot be fixed where it happens.
00111  *
00112  *
00113  * @see example_exception.cpp
00114  * @ingroup FCL
00115  * @ingroup Exceptions
00116  *
00117  * @author Tim Niemueller
00118  */
00119 /** @var Exception::messages
00120  * List of messages. Should not be NULL. Messages are append with append().
00121  * Using a custom list to avoid including STL stuff in this core file.
00122  * @see append()
00123  */
00124 /** @var Exception::messages_iterator
00125  * Iterator to iterate over messages
00126  */
00127 /** @var Exception::messages_end
00128  * Pointer that points to the very last message. Used for fast appending.
00129  */
00130 /** @var Exception::messages_mutex
00131  * Mutex to protect operations on messages list.
00132  */
00133 /** @var Exception::_errno
00134  * Error number, should be used if the error was caused by a method that supplies
00135  * errno.
00136  */
00137 
00138 
00139 /** Constructor.
00140  * Constructs a new exception with the given message.
00141  * @param format The format of the primary message. Supports the same
00142  * arguments as append(). The message is copied and not just referenced.
00143  * Thus the memory has to be freed if it is a dynamic  string on the heap.
00144  */
00145 Exception::Exception(const char *format, ...) throw()
00146 { 
00147   messages_mutex = new Mutex();
00148 
00149   _errno = 0;
00150   __type_id = "unknown";
00151 
00152   messages = NULL;
00153   messages_end = NULL;
00154   messages_iterator = NULL;
00155 
00156   if ( format != NULL ) {
00157     va_list arg;
00158     va_start(arg, format);
00159     append_nolock_va(format, arg);
00160     va_end(arg);
00161   } else {
00162     append_nolock("Unnkown Exception");
00163   }
00164 }
00165 
00166 
00167 /** Constructor.
00168  * Constructs a new exception with the given message and errno value. This
00169  * is particularly handy when throwing the exception after a function failed
00170  * that returns an error code in errno. 
00171  * @param errno error number
00172  * @param format The format of the primary message. Supports the same
00173  * arguments as append(). The message is copied and not just referenced.
00174  * Thus the memory has to be freed if it is a dynamic  string on the heap.
00175  */
00176 Exception::Exception(int errno, const char *format, ...) throw()
00177 {
00178   messages_mutex = new Mutex();
00179 
00180   _errno = errno;
00181   __type_id = "unknown";
00182 
00183   messages = NULL;
00184   messages_end = NULL;
00185   messages_iterator = NULL;
00186 
00187   if ( format != NULL ) {
00188     va_list arg;
00189     va_start(arg, format);
00190     char *ext_format;
00191     if ( asprintf(&ext_format, "%s (errno: %i, %s)", format, errno, strerror(errno)) == -1 ) {
00192       append_nolock_va(format, arg);
00193     } else {
00194       append_nolock_va(ext_format, arg);
00195       free(ext_format);
00196     }
00197     va_end(arg);
00198   } else {
00199     append_nolock("Exception with errno=%i (%s)", errno, strerror(errno));
00200   }
00201 }
00202 
00203 
00204 /** Copy constructor.
00205  * The copy constructor is worth some extra discussion. If you do an exception
00206  * by value (which you shouldn't in the first place since this will generate a
00207  * copy, only do this if you can't avoid it for some reason. Not if you only
00208  * THINK that you can't avoid it) the copy constructor is called. If your catch
00209  * statements reads like
00210  * @code
00211  *   try {
00212  *     ...
00213  *   } catch (Exception e) {
00214  *     ...
00215  *   }
00216  * @endcode
00217  * then a copy will be created for the catch block. You throw the exception with
00218  * something like
00219  * @code
00220  *   throw Exception("Boom");
00221  * @endcode
00222  * This will create an Exception which is valid in the block where you throw the
00223  * exception. Now for the catch block a copy is created. Since the exception
00224  * holds a pointer on the heap the implicit copy constructor would just copy
00225  * the pointer, not the data. So both exceptions point to the same data (to the
00226  * message for the base exception). If now both destructors for the exception
00227  * are called they both try to free the very same memory. Of course the second
00228  * destructor will cause a disaster. If you are lucky your glibc detectes the
00229  * problem an kills the application. If you are not that fortunate you will
00230  * cause very strange behaviour of your application.
00231  *
00232  * In general you should not have to worry about this. But if you choose to have
00233  * own storage on the heap using either new, malloc or a method that returns
00234  * memory on the heap (like strdup()) you have to write your own copy contructor
00235  * and copy the memory area or take care that only one exception frees the memory.
00236  * @param exc Exception to copy
00237  */
00238 Exception::Exception(const Exception &exc) throw()
00239 {
00240   messages_mutex = new Mutex();
00241 
00242   messages = NULL;
00243   messages_end = NULL;
00244   messages_iterator = NULL;
00245 
00246   _errno = exc._errno;
00247   __type_id = exc.__type_id;
00248   copy_messages(exc);
00249 }
00250 
00251 
00252 /** Constructor for subclasses.
00253  * This constructor can be used in subclasses is some processing code is
00254  * needed (like sprintf) to assign the message. At least assign the empty
00255  * string to the message.
00256  */
00257 Exception::Exception() throw()
00258 {
00259   messages_mutex = new Mutex();
00260   _errno = 0;
00261   __type_id = "unknown";
00262   messages = NULL;
00263   messages_end = NULL;
00264   messages_iterator = NULL;
00265 }
00266 
00267 
00268 /** Destructor. */
00269 Exception::~Exception() throw()
00270 {
00271   message_list_t *msg_this;
00272   messages_iterator = messages;
00273   while ( messages_iterator ) {
00274     free(messages_iterator->msg);
00275     msg_this = messages_iterator;
00276     messages_iterator = messages_iterator->next;
00277     free(msg_this);
00278   }
00279   messages = NULL;
00280   messages_end = NULL;
00281   delete messages_mutex;
00282 }
00283 
00284 
00285 /** Set exception type ID.
00286  * Set the type ID of this exception.
00287  * @param id new type ID, note that this must be a static string which is
00288  * guaranteed to exist for the whole lifetime of the exception.
00289  * @see Exception::type_id()
00290  */
00291 void
00292 Exception::set_type_id(const char *id)
00293 {
00294   __type_id = id;
00295 }
00296 
00297 
00298 /** Get type ID.
00299  * Exceptions can have a type ID. This can be used to avoid having to declare
00300  * numerous specific exception sub-classes to different errors, if it is
00301  * essential to be able to differentiate them in the exception handling code.
00302  * The type ID is a free-form string. It should NOT contain any message, rather
00303  * it should be a one-word internal identifier that is never leaked to the user
00304  * of the software, i.e. it is not printed anywhere. Note that the ID must be
00305  * a static string, which exists for the whole life time of the exception, is
00306  * generally not in a dynamically allocated memory (this very exception could
00307  * indicate memory shortage). This also makes it thread-safe.
00308  * @return type ID
00309  */
00310 const char *
00311 Exception::type_id() const
00312 {
00313   return __type_id;
00314 }
00315 
00316 
00317 /** Prepend messages to the message list.
00318  * @param format format of the message to prepend, see printf(3) for details about formatting
00319  * options.
00320  */
00321 void
00322 Exception::prepend(const char *format, ...) throw()
00323 {
00324   // do not append empty messages
00325   if (format == NULL)  return;
00326 
00327   va_list arg;
00328   va_start(arg, format);
00329   messages_mutex->lock();
00330   prepend_nolock_va(format, arg);
00331   messages_mutex->unlock();
00332   va_end(arg);
00333 }
00334 
00335 
00336 /** Append messages to the message list.
00337  * @param format format of the message to append, see printf(3) for details about formatting
00338  * options.
00339  */
00340 void
00341 Exception::append(const char *format, ...) throw()
00342 {
00343   // do not append empty messages
00344   if (format == NULL)  return;
00345 
00346   va_list arg;
00347   va_start(arg, format);
00348   messages_mutex->lock();
00349   append_nolock_va(format, arg);
00350   messages_mutex->unlock();
00351   va_end(arg);
00352 }
00353 
00354 
00355 /** Append messages to the message list.
00356  * @param format format of the message to append, see printf(3) for details about formatting
00357  * options.
00358  * @param va va_list with arguments matching the format
00359  */
00360 void
00361 Exception::append_va(const char *format, va_list va) throw()
00362 {
00363   // do not append empty messages
00364   if (format == NULL)  return;
00365 
00366   messages_mutex->lock();
00367   append_nolock_va(format, va);
00368   messages_mutex->unlock();
00369 }
00370 
00371 
00372 /** Append message that are from another Exception.
00373  * @param e Exception to copy messages from
00374  */
00375 void
00376 Exception::append(const Exception &e) throw()
00377 {
00378   copy_messages(e);  
00379 }
00380 
00381 
00382 /** Append messages without lock.
00383  * this can be used to append messages without locking the mutex if the mutex
00384  * has been locked already to append many messages and keep their order intact
00385  * and thus to prevent messages to be appended inbetween.
00386  * Used for example in copy constructor.
00387  * @param format The format of the primary message. Supports the same
00388  * arguments as append(). The message is copied and not just referenced.
00389  * Thus the memory has to be freed if it is a dynamic  string on the heap.
00390  */
00391 void
00392 Exception::append_nolock(const char *format, ...) throw()
00393 {
00394   va_list arg;
00395   va_start(arg, format);
00396 
00397   char *msg;
00398   if ( vasprintf(&msg, format, arg) == -1 ) {
00399     msg = strdup(format);
00400   }
00401 
00402   va_end(arg);
00403 
00404   if ( messages == NULL ) {
00405     // This is our first message
00406     messages = (message_list_t *)malloc(sizeof(message_list_t));
00407     messages->next = NULL;
00408     messages->msg  = msg;
00409     messages_end = messages;
00410   } else {
00411     message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
00412     ml->next = NULL;
00413     ml->msg = msg;
00414     messages_end->next = ml;
00415     messages_end = ml;
00416   }
00417 }
00418 
00419 
00420 /** Prepend messages without lock by formatted string.
00421  * This can be used to append messages without locking the mutex if the mutex
00422  * has been locked already to append many messages and keep their order intact
00423  * and thus to prevent messages to be appended inbetween.
00424  * Used for example in copy constructor.
00425  * @param format format of the message to be appended
00426  * @param ap argument va_list for format
00427  */
00428 void
00429 Exception::prepend_nolock_va(const char *format, va_list ap) throw()
00430 {
00431   char *msg;
00432   if ( vasprintf(&msg, format, ap) == -1 ) {
00433     msg = strdup(format);
00434   }
00435 
00436   if ( messages == NULL ) {
00437     // This is our first message
00438     messages = (message_list_t *)malloc(sizeof(message_list_t));
00439     messages->next = NULL;
00440     messages->msg  = msg;
00441     messages_end = messages;
00442   } else {
00443     message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
00444     ml->next = messages;
00445     ml->msg = msg;
00446     messages = ml;
00447   }
00448 }
00449 
00450 
00451 /** Append messages without lock by formatted string.
00452  * this can be used to append messages without locking the mutex if the mutex
00453  * has been locked already to append many messages and keep their order intact
00454  * and thus to prevent messages to be appended inbetween.
00455  * Used for example in copy constructor.
00456  * @param format format of the message to be appended
00457  * @param ap argument va_list for format
00458  */
00459 void
00460 Exception::append_nolock_va(const char *format, va_list ap) throw()
00461 {
00462   char *msg;
00463   if ( vasprintf(&msg, format, ap) == -1 ) {
00464     msg = strdup(format);
00465   }
00466 
00467   if ( messages == NULL ) {
00468     // This is our first message
00469     messages = (message_list_t *)malloc(sizeof(message_list_t));
00470     messages->next = NULL;
00471     messages->msg  = msg;
00472     messages_end = messages;
00473   } else {
00474     message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
00475     ml->next = NULL;
00476     ml->msg = msg;
00477     messages_end->next = ml;
00478     messages_end = ml;
00479   }
00480 }
00481 
00482 
00483 /** Append message without copying.
00484  * Can be used in subclasses to append messages that have been allocated
00485  * on the heap. Use with extreme care. Do not add constant strings! This would
00486  * cause your application to crash since the destructor will try to free all
00487  * messages. The message list is not locked.
00488  * @param msg Message to append.
00489  */
00490 void
00491 Exception::append_nolock_nocopy(char *msg) throw()
00492 {
00493   if ( messages == NULL ) {
00494     // This is our first message
00495     messages = (message_list_t *)malloc(sizeof(message_list_t));
00496     messages->next = NULL;
00497     messages->msg  = msg;
00498     messages_end = messages;
00499   } else {
00500     message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
00501     ml->next = NULL;
00502     ml->msg = msg;
00503     messages_end->next = ml;
00504     messages_end = ml;
00505   }  
00506 }
00507 
00508 
00509 /** Assign an Exception.
00510  * As this is one of the Big Three (see C++ FAQ at
00511  * http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10) this
00512  * is needed because we already need a copy constructor. Read about the
00513  * copy constructor why this is the case.
00514  * @see Exception(const Exception &exc)
00515  * @param exc The exception with the values to assign to this exception.
00516  * @return reference to this object. Allows assignment chaining.
00517  */
00518 Exception &
00519 Exception::operator=(const Exception &exc) throw()
00520 {
00521   messages_mutex = new Mutex();
00522   copy_messages(exc);
00523 
00524   return *this;
00525 }
00526 
00527 
00528 /** Copy messages from given exception.
00529  * Copies the messages from exc to this exception.
00530  * @param exc Exception to copy messages from.
00531  */
00532 void
00533 Exception::copy_messages(const Exception &exc) throw()
00534 {
00535   messages_mutex->lock();
00536   exc.messages_mutex->lock();
00537 
00538   // copy messages
00539   messages_iterator = exc.messages;
00540   while ( messages_iterator ) {
00541     append_nolock(messages_iterator->msg);
00542     messages_iterator = messages_iterator->next;
00543   }
00544 
00545   exc.messages_mutex->unlock();
00546   messages_mutex->unlock();
00547 }
00548 
00549 
00550 /** This can be used to throw this exception.
00551  * This can be used to throw this exception instance. This is a precaution if
00552  * it is needed. See C++ FAQ 17.10.
00553  */
00554 void
00555 Exception::raise()
00556 {
00557   throw *this;
00558 }
00559 
00560 
00561 /** Prints a backtrace. */
00562 void
00563 Exception::print_backtrace() const throw()
00564 {
00565 #ifdef HAVE_EXECINFO
00566   void * array[25];
00567   int size = backtrace(array, 25);
00568   char ** symbols = backtrace_symbols(array, size);
00569 
00570   printf("Backtrace:\n");
00571   for (int i = 0; i < size; ++i) {
00572     printf("  %s\n", symbols[i]);
00573   }
00574   
00575   free(symbols);
00576 #else
00577   printf("Backtrace not available on current system\n");
00578 #endif
00579 }
00580 
00581 
00582 /** Generate backtrace string.
00583  * @return freshly allocated string of backtrace. Free after you are done.
00584  */
00585 char *
00586 Exception::generate_backtrace() const throw()
00587 {
00588 #ifdef HAVE_BACKTRACE
00589   void * array[25];
00590   int size = backtrace(array, 25);
00591   char ** symbols = backtrace_symbols(array, size);
00592   
00593   size_t total_size = 1; //null termination
00594   for (int i = 0; i < size; ++i) {
00595     total_size += strlen(symbols[i]) + 1;
00596   }
00597   char *rv = (char *)calloc(1, total_size);
00598   char *r = rv;
00599   for (int i = 0; i < size; ++i) {
00600     sprintf(r, "%s\n", symbols[i]);
00601     r += strlen(symbols[i]);
00602   }
00603   
00604   free(symbols);
00605 #else
00606   char *rv = strdup("Backtrace not available on current system\n");
00607 #endif
00608 
00609   return rv;
00610 }
00611 
00612 
00613 /** Prints trace to stderr.
00614  * This prints out a message trace of all messages appended to the exception
00615  * in chronological order starting with the oldest (first message appended
00616  * via constructor or append(). Output will be sent to stderr.
00617  */
00618 void
00619 Exception::print_trace() throw()
00620 {
00621   messages_mutex->lock();
00622   fprintf(stderr,
00623           "=================================================== BEGIN OF EXCEPTION =====\n");
00624   if ( messages == NULL ) {
00625     fprintf(stderr, "No messages recorded.\n");
00626   } else {
00627     messages_iterator = messages;
00628     while ( messages_iterator ) {
00629       fprintf(stderr, "%s\n", messages_iterator->msg);
00630       messages_iterator = messages_iterator->next;
00631     }
00632   }
00633   fprintf(stderr,
00634           "=================================================== END OF EXCEPTION =======\n");
00635   messages_mutex->unlock();
00636 }
00637 
00638 
00639 /** Get errno.
00640  * @return error number, may be 0 if not set
00641  */
00642 int
00643 Exception::get_errno() throw()
00644 {
00645   return _errno;
00646 }
00647 
00648 
00649 /** Get primary string.
00650  * Messages are stored in a list. The first entry in this list is called primary
00651  * message. This is why it is important to have a meaningful first message!
00652  * @return Returns a constant char pointer with the message. The message is
00653  * private to the exception and may not be modified or freed (hence const)
00654  * If no message has been set "Unknown error" is returned. This method may be
00655  * overidden by other exceptions.
00656  * This method is also called by the runtime system if the exception was not
00657  * caught and resulted in a program termination.
00658  * @return string describing the general cause of the current error
00659  */
00660 const char *
00661 Exception::what() const throw()
00662 {
00663 #ifdef HAVE_EXECINFO
00664   print_backtrace();
00665 #endif
00666   if ( messages != NULL ) {
00667     return messages->msg;
00668   } else {
00669     return "Unknown error";
00670   }
00671 }
00672 
00673 
00674 /** Get iterator for messages.
00675  * @return iterator for messages
00676  */
00677 Exception::iterator
00678 Exception::begin() throw()
00679 {
00680   Exception::iterator i(messages);
00681   return i;
00682 }
00683 
00684 
00685 /** @class Exception::iterator <core/exception.h>
00686  * Message iterator for exceptions.
00687  * This iterator allows for iterating over all messages carried by an Exception.
00688  * @author Tim Niemueller
00689  */
00690 
00691 /** Get end iterator for messages.
00692  * @return end iterator for messages.
00693  */
00694 Exception::iterator
00695 Exception::end() throw()
00696 {
00697   Exception::iterator i;
00698   return i;
00699 }
00700 
00701 
00702 /** Constructor.
00703  * @param message_list list of messages, will be used unlocked so use
00704  * with care.
00705  */
00706 Exception::iterator::iterator(message_list_t *message_list)
00707 {
00708   mlist = message_list;
00709 }
00710 
00711 
00712 /** Plain constructor.
00713  * Creates a new invalid iterator (same as Exception::end()).
00714  */
00715 Exception::iterator::iterator()
00716 {
00717   this->mlist = NULL;
00718 }
00719 
00720 
00721 /** Copy constructor.
00722  * @param i iterator to copy
00723  */
00724 Exception::iterator::iterator(const Exception::iterator & i)
00725 {
00726   this->mlist = i.mlist;
00727 }
00728 
00729 
00730 /** Prefix ++ operator.
00731  * @return reference to this iterator after advancing.
00732  */
00733 Exception::iterator &
00734 Exception::iterator::operator++()
00735 {
00736   if ( mlist != NULL ) {
00737     mlist = mlist->next;
00738   }
00739   return *this;
00740 }
00741 
00742 
00743 /** Postfix ++ operator.
00744  * @param inc used to denote postfix operator
00745  * @return copy of iterator before advancing.
00746  */
00747 Exception::iterator
00748 Exception::iterator::operator++(int inc)
00749 {
00750   iterator i(mlist);
00751   if ( mlist != NULL ) {
00752     mlist = mlist->next;
00753   }
00754   return i;
00755 }
00756 
00757 
00758 /** Check equality.
00759  * @param i iterator to compare to
00760  * @return true, if iterators point to the same message, false otherwise
00761  */
00762 bool
00763 Exception::iterator::operator==(const iterator & i) const
00764 {
00765   return (mlist == i.mlist);
00766 }
00767 
00768 
00769 /** Check inequality.
00770  * @param i iterator to compare to
00771  * @return true, if iterators point to different messages, false otherwise
00772  */
00773 bool
00774 Exception::iterator::operator!=(const iterator & i) const
00775 {
00776   return (mlist != i.mlist);
00777 }
00778 
00779 
00780 /** Get current message.
00781  * Get message at current position. Returns NULL for the invalid ieterator.
00782  * @return message or NULL if iterator is invalid
00783  */
00784 const char *
00785 Exception::iterator::operator* () const
00786 {
00787   if ( mlist != NULL ) {
00788     return mlist->msg;
00789   } else {
00790     return NULL;
00791   }
00792 }
00793 
00794 
00795 /** Assignment operator.
00796  * @param i iterator to assign to this iterator.
00797  * @return reference to this iterator.
00798  */
00799 Exception::iterator &
00800 Exception::iterator::operator=(const iterator &i)
00801 {
00802   this->mlist = i.mlist;
00803   return *this;
00804 }
00805 
00806 
00807 } // end namespace fawkes

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1