/** @file

    $Id$

    $Date$
    $Author$

    @copy &copy; Marc W&auml;ckerlin
    @license LGPL, see file <a href="license.html">COPYING</a>

    $Log$
    Revision 1.3  2005/11/29 12:39:42  marc
    make it compilable with gcc 4.0.2 and newer doxygen

    Revision 1.2  2005/02/18 15:53:07  marc
    I'm so stupid, there's strerror for mapping errno to a string...

    Revision 1.1  2005/02/08 12:30:22  marc
    new in release 1.8.0


         1         2         3         4         5         6         7         8
    5678901234567890123456789012345678901234567890123456789012345678901234567890
*/

#ifndef __MRW_ERRNO_HPP__
#define __MRW_ERRNO_HPP__

#include <mrw/exception.hpp>
#include <string>
#include <map>

namespace mrw {
  
  /** @addtogroup exceptions

      In addition to the reimplementation of the standard exceptions,
      There is also a class mrw::Errno to handle UNIX C library errno
      and an exception class mrw::unix_error to that uses mrw::Errno
      to convert @c errno into a meaningful string and that offers
      facilities to handle failed UNIX C library calls. */
  //@{
  
  /** @brief Stores a UNIX errno error number and converts it to string.

      @pre \#include <mrw/errno.hpp> */
  class Errno {

      //................................................................ methods
    public:
      
      /// stores the actual @c errno
      Errno() throw();
      
      /// returns a string that describes the error
      operator std::string() const throw(std::bad_exception);
      
      /// returns a string that describes the error
      std::string string() const throw(std::bad_exception);
      
      /// returns the @c errno stored in the constructor
      operator int() const throw() {
        return _errno;
      }
      
      /// returns the @c errno stored in the constructor
      int numerical() const throw() {
        return _errno;
      }

      //.............................................................. variables
    private:
      
      int _errno;
      
  };

  /** @brief to be thrown when a unix system call fails, evaluates @c errno

      @pre \#include <mrw/errno.hpp> */
  
  class unix_error: public mrw::runtime_error {

      //................................................................ methods
    public:
      
      /** @brief convert return value of a UNIX system call that sets @c errno
                 to an exception

          Thought to be used like this:
          @code
          mrw::unix_error::check(sockfd=::socket(domain, type, 0), "socket");
          @endcode
          or even simpler with a macro (sets text automatically):
          @code
          MRW_CHECK_UNIX(sockfd=::socket(domain, type, 0));
          @endcode
          this is the same (but simpler to write) than:
          @code
          if ((sockfd=::socket(domain, type, 0)<0)
            throw mrw::unix_error("socket");
          @endcode

          @param res the result of a UNIX C library operation
          @param arg additional error information
          @throw mrw::unix_error if res<0 */
      
      static void check(int res, const std::string& arg)
        throw(std::exception) {
        if (res<0) throw mrw::unix_error(arg);
      }

      /** @brief convert return value of a UNIX system call that sets @c errno
                 to an exception
          
          Thought to be used like this:
          @code
          MRW_CHECK_UNIX(sockfd=::socket(domain, type, 0));
          @endcode
          this is the same (but simpler to write) than:
          @code
          if ((sockfd=::socket(domain, type, 0)<0)
            throw mrw::unix_error("sockfd=::socket(domain, type, 0)");
          @endcode

          @param CMD a UNIX operation to be executed and checked
          @throw mrw::unix_error if return value of CMD < 0 */
#     define MRW_CHECK_UNIX(CMD) mrw::unix_error::check((CMD), # CMD)

      /** @brief construct an exception that stores the @c errno given an
                 additional error text

          The error text returned by what() is:

          "unix error: " + Errno().string() + "; " + arg

          @param arg additional error text */
      
      unix_error(const std::string& arg) throw(std::bad_exception):
        mrw::runtime_error(std::string("unix error: ")+Errno().string()
                           +"; "+arg) {
      }
  };

  //@}
  
}
#endif
