error_code.cpp

00001 //  error_code support implementation file  ----------------------------------//
00002 
00003 //  Copyright Beman Dawes 2002, 2006
00004 
00005 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
00006 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00007 
00008 //  See library home page at http://www.boost.org/libs/system
00009 
00010 //----------------------------------------------------------------------------//
00011 
00012 //  VC++ 8.0 warns on usage of certain Standard Library and API functions that
00013 //  can be cause buffer overruns or other possible security issues if misused.
00014 //  See http://msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC/default.aspx
00015 //  But the wording of the warning is misleading and unsettling, there are no
00016 //  portable alternative functions, and VC++ 8.0's own libraries use the
00017 //  functions in question. So turn off the warnings.
00018 #define _CRT_SECURE_NO_DEPRECATE
00019 #define _SCL_SECURE_NO_DEPRECATE
00020 
00021 // define BOOST_SYSTEM_SOURCE so that <boost/system/config.hpp> knows
00022 // the library is being built (possibly exporting rather than importing code)
00023 #define BOOST_SYSTEM_SOURCE 
00024 
00025 #include <boost/system/config.hpp>
00026 #include <boost/system/error_code.hpp>
00027 #include <boost/cerrno.hpp>
00028 #include <vector>
00029 #include <cstdlib>
00030 #include <cassert>
00031 
00032 using namespace boost::system;
00033 using namespace boost::system::posix_error;
00034 
00035 #include <cstring> // for strerror/strerror_r
00036 
00037 # if defined( BOOST_WINDOWS_API )
00038 #   include <windows.h>
00039 #   ifndef ERROR_INCORRECT_SIZE
00040 #    define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS
00041 #   endif
00042 # endif
00043 
00044 //----------------------------------------------------------------------------//
00045 
00046 namespace
00047 {
00048   //  standard error categories  -------------------------------------------//
00049 
00050   class posix_error_category : public error_category
00051   {
00052   public:
00053     posix_error_category(){}
00054     const char *   name() const;
00055     std::string    message( int ev ) const;
00056   };
00057 
00058   class system_error_category : public error_category
00059   {
00060   public:
00061     system_error_category(){}
00062     const char *        name() const;
00063     std::string         message( int ev ) const;
00064     error_condition     default_error_condition( int ev ) const;
00065   };
00066 
00067   //  posix_error_category implementation  ---------------------------------//
00068 
00069   const char * posix_error_category::name() const
00070   {
00071     return "POSIX";
00072   }
00073 
00074   std::string posix_error_category::message( int ev ) const
00075   {
00076   // strerror_r is preferred because it is always thread safe,
00077   // however, we fallback to strerror in certain cases because:
00078   //   -- Windows doesn't provide strerror_r.
00079   //   -- HP and Sundo provide strerror_r on newer systems, but there is
00080   //      no way to tell if is available at runtime and in any case their
00081   //      versions of strerror are thread safe anyhow.
00082   //   -- Linux only sometimes provides strerror_r.
00083   //   -- Tru64 provides strerror_r only when compiled -pthread.
00084   //   -- VMS doesn't provide strerror_r, but on this platform, strerror is
00085   //      thread safe.
00086   # if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\
00087      || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\
00088      || (defined(__osf__) && !defined(_REENTRANT))\
00089      || (defined(__vms))
00090       const char * c_str = std::strerror( ev );
00091       return std::string( c_str ? c_str : "Unknown error" );
00092   # else
00093       char buf[64];
00094       char * bp = buf;
00095       std::size_t sz = sizeof(buf);
00096   #  if defined(__CYGWIN__) || defined(__USE_GNU)
00097       // Oddball version of strerror_r
00098       const char * c_str = strerror_r( ev, bp, sz );
00099       return std::string( c_str ? c_str : "Unknown error" );
00100   #  else
00101       // POSIX version of strerror_r
00102       int result;
00103       for (;;)
00104       {
00105         // strerror_r returns 0 on success, otherwise ERANGE if buffer too small,
00106         // invalid_argument if ev not a valid error number
00107   #  if defined (__sgi)
00108         const char * c_str = strerror( ev );
00109         result = 0;
00110         return std::string( c_str ? c_str : "Unknown error" );
00111   #  else
00112         result = strerror_r( ev, bp, sz );
00113   #  endif
00114         if (result == 0 )
00115           break;
00116         else
00117         {
00118   #  if defined(__linux)
00119           // Linux strerror_r returns -1 on error, with error number in errno
00120           result = errno;
00121   #  endif
00122           if ( result !=  ERANGE ) break;
00123         if ( sz > sizeof(buf) ) std::free( bp );
00124         sz *= 2;
00125         if ( (bp = static_cast<char*>(std::malloc( sz ))) == 0 )
00126           return std::string( "ENOMEM" );
00127         }
00128       }
00129       try
00130       {
00131       std::string msg( ( result == invalid_argument ) ? "Unknown error" : bp );
00132       if ( sz > sizeof(buf) ) std::free( bp );
00133         sz = 0;
00134       return msg;
00135       }
00136       catch(...)
00137       {
00138         if ( sz > sizeof(buf) ) std::free( bp );
00139         throw;
00140       }
00141   #  endif
00142   # endif
00143   }
00144   //  system_error_category implementation  --------------------------------// 
00145 
00146   const char * system_error_category::name() const
00147   {
00148     return "system";
00149   }
00150 
00151   error_condition system_error_category::default_error_condition( int ev ) const
00152   {
00153     switch ( ev )
00154     {
00155     case 0: return make_error_condition( success );
00156   # if defined(BOOST_POSIX_API)
00157     // POSIX-like O/S -> posix_errno decode table  ---------------------------//
00158     case E2BIG: return make_error_condition( argument_list_too_long );
00159     case EACCES: return make_error_condition( permission_denied );
00160     case EADDRINUSE: return make_error_condition( address_in_use );
00161     case EADDRNOTAVAIL: return make_error_condition( address_not_available );
00162     case EAFNOSUPPORT: return make_error_condition( address_family_not_supported );
00163     case EAGAIN: return make_error_condition( resource_unavailable_try_again );
00164     case EALREADY: return make_error_condition( connection_already_in_progress );
00165     case EBADF: return make_error_condition( bad_file_descriptor );
00166     case EBADMSG: return make_error_condition( bad_message );
00167     case EBUSY: return make_error_condition( device_or_resource_busy );
00168     case ECANCELED: return make_error_condition( operation_canceled );
00169     case ECHILD: return make_error_condition( no_child_process );
00170     case ECONNABORTED: return make_error_condition( connection_aborted );
00171     case ECONNREFUSED: return make_error_condition( connection_refused );
00172     case ECONNRESET: return make_error_condition( connection_reset );
00173     case EDEADLK: return make_error_condition( resource_deadlock_would_occur );
00174     case EDESTADDRREQ: return make_error_condition( destination_address_required );
00175     case EDOM: return make_error_condition( argument_out_of_domain );
00176     case EEXIST: return make_error_condition( file_exists );
00177     case EFAULT: return make_error_condition( bad_address );
00178     case EFBIG: return make_error_condition( file_too_large );
00179     case EHOSTUNREACH: return make_error_condition( host_unreachable );
00180     case EIDRM: return make_error_condition( identifier_removed );
00181     case EILSEQ: return make_error_condition( illegal_byte_sequence );
00182     case EINPROGRESS: return make_error_condition( operation_in_progress );
00183     case EINTR: return make_error_condition( interrupted );
00184     case EINVAL: return make_error_condition( invalid_argument );
00185     case EIO: return make_error_condition( io_error );
00186     case EISCONN: return make_error_condition( already_connected );
00187     case EISDIR: return make_error_condition( is_a_directory );
00188     case ELOOP: return make_error_condition( too_many_synbolic_link_levels );
00189     case EMFILE: return make_error_condition( too_many_files_open );
00190     case EMLINK: return make_error_condition( too_many_links );
00191     case EMSGSIZE: return make_error_condition( message_size );
00192     case ENAMETOOLONG: return make_error_condition( filename_too_long );
00193     case ENETDOWN: return make_error_condition( network_down );
00194     case ENETRESET: return make_error_condition( network_reset );
00195     case ENETUNREACH: return make_error_condition( network_unreachable );
00196     case ENFILE: return make_error_condition( too_many_files_open_in_system );
00197     case ENOBUFS: return make_error_condition( no_buffer_space );
00198     case ENODATA: return make_error_condition( no_message_available );
00199     case ENODEV: return make_error_condition( no_such_device );
00200     case ENOENT: return make_error_condition( no_such_file_or_directory );
00201     case ENOEXEC: return make_error_condition( executable_format_error );
00202     case ENOLCK: return make_error_condition( no_lock_available );
00203     case ENOLINK: return make_error_condition( no_link );
00204     case ENOMEM: return make_error_condition( not_enough_memory );
00205     case ENOMSG: return make_error_condition( no_message );
00206     case ENOPROTOOPT: return make_error_condition( no_protocol_option );
00207     case ENOSPC: return make_error_condition( no_space_on_device );
00208     case ENOSR: return make_error_condition( no_stream_resources );
00209     case ENOSTR: return make_error_condition( not_a_stream );
00210     case ENOSYS: return make_error_condition( function_not_supported );
00211     case ENOTCONN: return make_error_condition( not_connected );
00212     case ENOTDIR: return make_error_condition( not_a_directory );
00213   # if ENOTEMPTY != EEXIST // AIX treats ENOTEMPTY and EEXIST as the same value
00214     case ENOTEMPTY: return make_error_condition( directory_not_empty );
00215   # endif // ENOTEMPTY != EEXIST
00216     case ENOTRECOVERABLE: return make_error_condition( state_not_recoverable );
00217     case ENOTSOCK: return make_error_condition( not_a_socket );
00218     case ENOTSUP: return make_error_condition( not_supported );
00219     case ENOTTY: return make_error_condition( inappropriate_io_control_operation );
00220     case ENXIO: return make_error_condition( no_such_device_or_address );
00221   # if EOPNOTSUPP != ENOTSUP
00222     case EOPNOTSUPP: return make_error_condition( operation_not_supported );
00223   # endif // EOPNOTSUPP != ENOTSUP
00224     case EOVERFLOW: return make_error_condition( value_too_large );
00225     case EOWNERDEAD: return make_error_condition( owner_dead );
00226     case EPERM: return make_error_condition( operation_not_permitted );
00227     case EPIPE: return make_error_condition( broken_pipe );
00228     case EPROTO: return make_error_condition( protocol_error );
00229     case EPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
00230     case EPROTOTYPE: return make_error_condition( wrong_protocol_type );
00231     case ERANGE: return make_error_condition( result_out_of_range );
00232     case EROFS: return make_error_condition( read_only_file_system );
00233     case ESPIPE: return make_error_condition( invalid_seek );
00234     case ESRCH: return make_error_condition( no_such_process );
00235     case ETIME: return make_error_condition( stream_timeout );
00236     case ETIMEDOUT: return make_error_condition( timed_out );
00237     case ETXTBSY: return make_error_condition( text_file_busy );
00238   # if EAGAIN != EWOULDBLOCK
00239     case EWOULDBLOCK: return make_error_condition( operation_would_block );
00240   # endif // EAGAIN != EWOULDBLOCK
00241     case EXDEV: return make_error_condition( cross_device_link );
00242   #else
00243     // Windows system -> posix_errno decode table  ---------------------------//
00244     // see WinError.h comments for descriptions of errors
00245     case ERROR_ACCESS_DENIED: return make_error_condition( permission_denied );
00246     case ERROR_ALREADY_EXISTS: return make_error_condition( file_exists );
00247     case ERROR_BAD_UNIT: return make_error_condition( no_such_device );
00248     case ERROR_BUFFER_OVERFLOW: return make_error_condition( filename_too_long );
00249     case ERROR_BUSY: return make_error_condition( device_or_resource_busy );
00250     case ERROR_BUSY_DRIVE: return make_error_condition( device_or_resource_busy );
00251     case ERROR_CANNOT_MAKE: return make_error_condition( permission_denied );
00252     case ERROR_CANTOPEN: return make_error_condition( io_error );
00253     case ERROR_CANTREAD: return make_error_condition( io_error );
00254     case ERROR_CANTWRITE: return make_error_condition( io_error );
00255     case ERROR_CURRENT_DIRECTORY: return make_error_condition( permission_denied );
00256     case ERROR_DEV_NOT_EXIST: return make_error_condition( no_such_device );
00257     case ERROR_DEVICE_IN_USE: return make_error_condition( device_or_resource_busy );
00258     case ERROR_DIR_NOT_EMPTY: return make_error_condition( directory_not_empty );
00259     case ERROR_DIRECTORY: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid"
00260     case ERROR_DISK_FULL: return make_error_condition( no_space_on_device );
00261     case ERROR_FILE_EXISTS: return make_error_condition( file_exists );
00262     case ERROR_FILE_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
00263     case ERROR_HANDLE_DISK_FULL: return make_error_condition( no_space_on_device );
00264     case ERROR_INVALID_ACCESS: return make_error_condition( permission_denied );
00265     case ERROR_INVALID_DRIVE: return make_error_condition( no_such_device );
00266     case ERROR_INVALID_FUNCTION: return make_error_condition( function_not_supported );
00267     case ERROR_INVALID_HANDLE: return make_error_condition( invalid_argument );
00268     case ERROR_INVALID_NAME: return make_error_condition( invalid_argument );
00269     case ERROR_LOCK_VIOLATION: return make_error_condition( no_lock_available );
00270     case ERROR_LOCKED: return make_error_condition( no_lock_available );
00271     case ERROR_NEGATIVE_SEEK: return make_error_condition( invalid_argument );
00272     case ERROR_NOACCESS: return make_error_condition( permission_denied );
00273     case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition( not_enough_memory );
00274     case ERROR_NOT_READY: return make_error_condition( resource_unavailable_try_again );
00275     case ERROR_NOT_SAME_DEVICE: return make_error_condition( cross_device_link );
00276     case ERROR_OPEN_FAILED: return make_error_condition( io_error );
00277     case ERROR_OPEN_FILES: return make_error_condition( device_or_resource_busy );
00278     case ERROR_OPERATION_ABORTED: return make_error_condition( operation_canceled );
00279     case ERROR_OUTOFMEMORY: return make_error_condition( not_enough_memory );
00280     case ERROR_PATH_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
00281     case ERROR_READ_FAULT: return make_error_condition( io_error );
00282     case ERROR_RETRY: return make_error_condition( resource_unavailable_try_again );
00283     case ERROR_SEEK: return make_error_condition( io_error );
00284     case ERROR_SHARING_VIOLATION: return make_error_condition( permission_denied );
00285     case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition( too_many_files_open );
00286     case ERROR_WRITE_FAULT: return make_error_condition( io_error );
00287     case ERROR_WRITE_PROTECT: return make_error_condition( permission_denied );
00288     case WSAEACCES: return make_error_condition( permission_denied );
00289     case WSAEADDRINUSE: return make_error_condition( address_in_use );
00290     case WSAEADDRNOTAVAIL: return make_error_condition( address_not_available );
00291     case WSAEAFNOSUPPORT: return make_error_condition( address_family_not_supported );
00292     case WSAEALREADY: return make_error_condition( connection_already_in_progress );
00293     case WSAEBADF: return make_error_condition( bad_file_descriptor );
00294     case WSAECONNABORTED: return make_error_condition( connection_aborted );
00295     case WSAECONNREFUSED: return make_error_condition( connection_refused );
00296     case WSAECONNRESET: return make_error_condition( connection_reset );
00297     case WSAEDESTADDRREQ: return make_error_condition( destination_address_required );
00298     case WSAEFAULT: return make_error_condition( bad_address );
00299     case WSAEHOSTUNREACH: return make_error_condition( host_unreachable );
00300     case WSAEINPROGRESS: return make_error_condition( operation_in_progress );
00301     case WSAEINTR: return make_error_condition( interrupted );
00302     case WSAEINVAL: return make_error_condition( invalid_argument );
00303     case WSAEISCONN: return make_error_condition( already_connected );
00304     case WSAEMFILE: return make_error_condition( too_many_files_open );
00305     case WSAEMSGSIZE: return make_error_condition( message_size );
00306     case WSAENAMETOOLONG: return make_error_condition( filename_too_long );
00307     case WSAENETDOWN: return make_error_condition( network_down );
00308     case WSAENETRESET: return make_error_condition( network_reset );
00309     case WSAENETUNREACH: return make_error_condition( network_unreachable );
00310     case WSAENOBUFS: return make_error_condition( no_buffer_space );
00311     case WSAENOPROTOOPT: return make_error_condition( no_protocol_option );
00312     case WSAENOTCONN: return make_error_condition( not_connected );
00313     case WSAENOTSOCK: return make_error_condition( not_a_socket );
00314     case WSAEOPNOTSUPP: return make_error_condition( operation_not_supported );
00315     case WSAEPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
00316     case WSAEPROTOTYPE: return make_error_condition( wrong_protocol_type );
00317     case WSAETIMEDOUT: return make_error_condition( timed_out );
00318     case WSAEWOULDBLOCK: return make_error_condition( operation_would_block );
00319   #endif
00320     default: return error_condition( ev, system_category );
00321     }
00322   }
00323 
00324 # if !defined( BOOST_WINDOWS_API )
00325 
00326   std::string system_error_category::message( int ev ) const
00327   {
00328     return posix_category.message( ev );
00329   }
00330 # else
00331 // TODO:
00332   
00333 //Some quick notes on the implementation (sorry for the noise if
00334 //someone has already mentioned them):
00335 //
00336 //- The ::LocalFree() usage isn't exception safe.
00337 //
00338 //See:
00339 //
00340 //<http://boost.cvs.sourceforge.net/boost/boost/boost/asio/system_exception.hpp?revision=1.1&view=markup>
00341 //
00342 //in the implementation of what() for an example.
00343 //
00344 //Cheers,
00345 //Chris
00346   std::string system_error_category::message( int ev ) const
00347   {
00348 # ifndef BOOST_NO_ANSI_APIS  
00349     LPVOID lpMsgBuf;
00350     DWORD retval = ::FormatMessageA( 
00351         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00352         FORMAT_MESSAGE_FROM_SYSTEM | 
00353         FORMAT_MESSAGE_IGNORE_INSERTS,
00354         NULL,
00355         ev,
00356         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00357         (LPSTR) &lpMsgBuf,
00358         0,
00359         NULL 
00360     );
00361     if (retval == 0)
00362         return std::string("Unknown error");
00363         
00364     std::string str( static_cast<LPCSTR>(lpMsgBuf) );
00365     ::LocalFree( lpMsgBuf ); // free the buffer
00366 # else  // WinCE workaround
00367     LPVOID lpMsgBuf;
00368     DWORD retval = ::FormatMessageW( 
00369         FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00370         FORMAT_MESSAGE_FROM_SYSTEM | 
00371         FORMAT_MESSAGE_IGNORE_INSERTS,
00372         NULL,
00373         ev,
00374         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00375         (LPWSTR) &lpMsgBuf,
00376         0,
00377         NULL 
00378     );
00379     if (retval == 0)
00380         return std::string("Unknown error");
00381     
00382     int num_chars = (wcslen( static_cast<LPCWSTR>(lpMsgBuf) ) + 1) * 2;
00383     LPSTR narrow_buffer = (LPSTR)_alloca( num_chars );
00384     if (::WideCharToMultiByte(CP_ACP, 0, static_cast<LPCWSTR>(lpMsgBuf), -1, narrow_buffer, num_chars, NULL, NULL) == 0)
00385         return std::string("Unknown error");
00386 
00387     std::string str( narrow_buffer );
00388     ::LocalFree( lpMsgBuf ); // free the buffer
00389 # endif
00390     while ( str.size()
00391       && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
00392         str.erase( str.size()-1 );
00393     if ( str.size() && str[str.size()-1] == '.' ) 
00394       { str.erase( str.size()-1 ); }
00395     return str;
00396   }
00397 # endif
00398 
00399 } // unnamed namespace
00400 
00401 namespace boost
00402 {
00403   namespace system
00404   {
00405 
00406     BOOST_SYSTEM_DECL const error_category & get_system_category()
00407     {
00408       static const system_error_category  system_category_const;
00409       return system_category_const;
00410     }
00411 
00412     BOOST_SYSTEM_DECL const error_category & get_posix_category()
00413     {
00414       static const posix_error_category posix_category_const;
00415       return posix_category_const;
00416     }
00417 
00418   } // namespace system
00419 } // namespace boost

Generated on Thu Jul 3 01:32:42 2008 for Astxx by  doxygen 1.5.6