From 04e774f337e5204e8bc6643047f182bba98b44b6 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 9 Sep 2007 14:59:10 +0000 Subject: [PATCH] Merge system and filesystem branches, bringing them in sync with N2415. Several filesystem bugs fixed, and current_path setter added. [SVN r39173] --- build/Jamfile | 56 --- doc/error_code.html | 7 +- include/boost/cerrno.hpp | 14 +- include/boost/system/config.hpp | 2 +- include/boost/system/error_code.hpp | 657 +++++++++++++++++++++++--- include/boost/system/system_error.hpp | 71 ++- src/error_code.cpp | 505 +++++++++++--------- test/Jamfile.v2 | 3 + test/error_code_test.cpp | 194 ++++++-- test/error_code_user_test.cpp | 433 ++++++++++++++--- test/header_only_test.cpp | 31 ++ test/system_error_test.cpp | 44 +- 12 files changed, 1466 insertions(+), 551 deletions(-) delete mode 100644 build/Jamfile create mode 100644 test/header_only_test.cpp diff --git a/build/Jamfile b/build/Jamfile deleted file mode 100644 index 2fe5983..0000000 --- a/build/Jamfile +++ /dev/null @@ -1,56 +0,0 @@ -# Boost System Library Build Jamfile - -# (C) Copyright Beman Dawes 2002, 2006 - -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or www.boost.org/LICENSE_1_0.txt) - -# See library home page at http://www.boost.org/libs/system - -subproject libs/system/build ; - -SOURCES = error_code ; - -lib boost_system - : ../src/$(SOURCES).cpp - : # build requirements - BOOST_SYSTEM_STATIC_LINK - $(BOOST_AUX_ROOT) $(BOOST_ROOT) - # common-variant-tag ensures that the library will - # be named according to the rules used by the install - # and auto-link features: - common-variant-tag - : debug release # build variants - ; - -dll boost_system - : ../src/$(SOURCES).cpp - : # build requirements - BOOST_SYSTEM_DYN_LINK=1 # tell source we're building dll's - dynamic # build only for dynamic runtimes - $(BOOST_AUX_ROOT) $(BOOST_ROOT) - # common-variant-tag ensures that the library will - # be named according to the rules used by the install - # and auto-link features: - common-variant-tag - : debug release # build variants - ; - -install system lib - : boost_system boost_system - ; - -stage stage/lib : boost_system boost_system - : - # copy to a path rooted at BOOST_ROOT: - $(BOOST_ROOT) - # make sure the names of the libraries are correctly named: - common-variant-tag - # add this target to the "stage" and "all" psuedo-targets: - stage - all - : - debug release - ; - -# end diff --git a/doc/error_code.html b/doc/error_code.html index 3674e50..6770103 100644 --- a/doc/error_code.html +++ b/doc/error_code.html @@ -30,6 +30,11 @@ code, usually one returned by an API. Class an identifier for a particular kind of error code. Users or third-parties may add additional error categories.

+

Builds

+

The system library is required by default. If the preprocessor macro name +BOOST_ERROR_CODE_HEADER_ONLY is defined, no object library or shared/DLL library +is required. Only one translation unit may defined BOOST_ERROR_CODE_HEADER_ONLY, +otherwise symbols will be multiply defined.

Synopsis

namespace boost
 {
@@ -254,7 +259,7 @@ choice for this type is pointer-to-member. 
   Oleg Abrosimov.


Last revised: -06 September, 2006

+30 August, 2007

© Copyright Beman Dawes, 2006

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/cerrno.hpp b/include/boost/cerrno.hpp index 3c717f0..afb6aac 100644 --- a/include/boost/cerrno.hpp +++ b/include/boost/cerrno.hpp @@ -1,14 +1,14 @@ -// Boost Filesystem cerrno.hpp header --------------------------------------// +// Boost cerrno.hpp header -------------------------------------------------// -// © Copyright Beman Dawes 2005. +// Copyright Beman Dawes 2005. // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -// See library home page at http://www.boost.org/libs/filesystem +// See library home page at http://www.boost.org/libs/system -#ifndef BOOST_FILESYSTEM_CERRNO_HPP -#define BOOST_FILESYSTEM_CERRNO_HPP +#ifndef BOOST_CERRNO_HPP +#define BOOST_CERRNO_HPP #include @@ -190,8 +190,4 @@ #define EILSEQ 9945 #endif -#define EBADHANDLE 9998 // bad handle -#define EOTHER 9999 // Other error not translatable - // to a POSIX errno value - #endif // include guard diff --git a/include/boost/system/config.hpp b/include/boost/system/config.hpp index 6709eb4..fa09099 100644 --- a/include/boost/system/config.hpp +++ b/include/boost/system/config.hpp @@ -28,7 +28,7 @@ // enable dynamic linking on Windows ---------------------------------------// //# if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK)) && defined(__BORLANDC__) && defined(__WIN32__) -//# error Dynamic linking Boost.Filesystem does not work for Borland; use static linking instead +//# error Dynamic linking Boost.System does not work for Borland; use static linking instead //# endif #ifdef BOOST_HAS_DECLSPEC // defined in config system diff --git a/include/boost/system/error_code.hpp b/include/boost/system/error_code.hpp index 479f2c3..02c6cef 100644 --- a/include/boost/system/error_code.hpp +++ b/include/boost/system/error_code.hpp @@ -1,22 +1,33 @@ // boost/system/error_code.hpp ---------------------------------------------// -// Copyright Beman Dawes 2006 +// Copyright Beman Dawes 2006, 2007 +// Copyright Christoper Kohlhoff 2007 // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// See library home page at http://www.boost.org/libs/filesystem +// See library home page at http://www.boost.org/libs/system -#ifndef BOOST_SYSTEM_ERROR_CODE_HPP -#define BOOST_SYSTEM_ERROR_CODE_HPP +#ifndef BOOST_ERROR_CODE_HPP +#define BOOST_ERROR_CODE_HPP #include #include #include #include -#include +#include +#include +#include #include #include +#include + +// TODO: undef these macros if not already defined +#include + +# ifdef BOOST_WINDOWS_API +# include +# endif #include // must be the last #include @@ -24,125 +35,623 @@ namespace boost { namespace system { -# ifndef BOOST_NO_STD_WSTRING // workaround Cygwin's lack of wstring_t - typedef std::wstring wstring_t; -# else - typedef std::basic_string wstring_t; -# endif class error_code; + class error_condition; - // typedefs for registering additional decoders -------------------------// + // "Concept" helpers ---------------------------------------------------// - typedef int (*errno_decoder)( const error_code & ); - typedef std::string (*message_decoder)( const error_code & ); - typedef wstring_t (*wmessage_decoder)( const error_code & ); + template< class T > + struct is_error_code_enum { static const bool value = false; }; + + template< class T > + struct is_error_condition_enum { static const bool value = false; }; + + // portable error_conditions -------------------------------------------// + + namespace posix + { + + enum posix_errno + { + success = 0, + address_family_not_supported = EAFNOSUPPORT, + address_in_use = EADDRINUSE, + address_not_available = EADDRNOTAVAIL, + already_connected = EISCONN, + argument_list_too_long = E2BIG, + argument_out_of_domain = EDOM, + bad_address = EFAULT, + bad_file_descriptor = EBADF, + bad_message = EBADMSG, + broken_pipe = EPIPE, + connection_aborted = ECONNABORTED, + connection_already_in_progress = EALREADY, + connection_refused = ECONNREFUSED, + connection_reset = ECONNRESET, + cross_device_link = EXDEV, + destination_address_required = EDESTADDRREQ, + device_or_resource_busy = EBUSY, + directory_not_empty = ENOTEMPTY, + executable_format_error = ENOEXEC, + file_exists = EEXIST, + file_too_large = EFBIG, + filename_too_long = ENAMETOOLONG, + function_not_supported = ENOSYS, + host_unreachable = EHOSTUNREACH, + identifier_removed = EIDRM, + illegal_byte_sequence = EILSEQ, + inappropriate_io_control_operation = ENOTTY, + interrupted = EINTR, + invalid_argument = EINVAL, + invalid_seek = ESPIPE, + io_error = EIO, + is_a_directory = EISDIR, + message_size = EMSGSIZE, + network_down = ENETDOWN, + network_reset = ENETRESET, + network_unreachable = ENETUNREACH, + no_buffer_space = ENOBUFS, + no_child_process = ECHILD, + no_link = ENOLINK, + no_lock_available = ENOLCK, + no_message_available = ENODATA, + no_message = ENOMSG, + no_protocol_option = ENOPROTOOPT, + no_space_on_device = ENOSPC, + no_stream_resources = ENOSR, + no_such_device_or_address = ENXIO, + no_such_device = ENODEV, + no_such_file_or_directory = ENOENT, + no_such_process = ESRCH, + not_a_directory = ENOTDIR, + not_a_socket = ENOTSOCK, + not_a_stream = ENOSTR, + not_connected = ENOTCONN, + not_enough_memory = ENOMEM, + not_supported = ENOTSUP, + operation_canceled = ECANCELED, + operation_in_progress = EINPROGRESS, + operation_not_permitted = EPERM, + operation_not_supported = EOPNOTSUPP, + operation_would_block = EWOULDBLOCK, + owner_dead = EOWNERDEAD, + permission_denied = EACCES, + protocol_error = EPROTO, + protocol_not_supported = EPROTONOSUPPORT, + read_only_file_system = EROFS, + resource_deadlock_would_occur = EDEADLK, + resource_unavailable_try_again = EAGAIN, + result_out_of_range = ERANGE, + state_not_recoverable = ENOTRECOVERABLE, + stream_timeout = ETIME, + text_file_busy = ETXTBSY, + timed_out = ETIMEDOUT, + too_many_files_open_in_system = ENFILE, + too_many_files_open = EMFILE, + too_many_links = EMLINK, + too_many_synbolic_link_levels = ELOOP, + value_too_large = EOVERFLOW, + wrong_protocol_type = EPROTOTYPE, + }; + + } // namespace posix + + template<> struct is_error_condition_enum + { static const bool value = true; }; // class error_category ------------------------------------------------// - class BOOST_SYSTEM_DECL error_category - : public boost::detail::identifier< uint_least32_t, error_category > + class error_category : public noncopyable { public: - error_category() - : boost::detail::identifier< uint_least32_t, error_category >(0){} - explicit error_category( value_type v ) - : boost::detail::identifier< uint_least32_t, error_category >(v){} + virtual ~error_category(){} + virtual const char * name() const; // see implementation note below + virtual std::string message( int ev ) const; // see implementation note below + virtual error_condition default_error_condition( int ev ) const; + virtual bool equivalent( int code, const error_condition & condition ) const; + virtual bool equivalent( const error_code & code, int condition ) const; + + bool operator==(const error_category & rhs) const { return this == &rhs; } + bool operator!=(const error_category & rhs) const { return this != &rhs; } + bool operator<( const error_category & rhs ) const + { + return std::less()( this, &rhs ); + } }; // predefined error categories -----------------------------------------// - const error_category errno_ecat(0); // unspecified value + BOOST_SYSTEM_DECL extern const error_category & posix_category; + BOOST_SYSTEM_DECL extern const error_category & system_category; -# ifdef BOOST_WINDOWS_API - const error_category native_ecat(1); // unspecified value -# else - const error_category native_ecat(0); // unspecified value -# endif + // deprecated synonyms + BOOST_SYSTEM_DECL extern const error_category & errno_ecat; // posix_category + BOOST_SYSTEM_DECL extern const error_category & native_ecat; // system_category - // class error_code ----------------------------------------------------// + // class error_condition -----------------------------------------------// - class BOOST_SYSTEM_DECL error_code + // error_conditions are portable, error_codes are system or lib specific + + class error_condition { public: - typedef boost::int_least32_t value_type; // constructors: - error_code() - : m_value(0), m_category(errno_ecat) {} - error_code( value_type val, error_category cat ) - : m_value(val), m_category(cat) {} + error_condition() : m_val(0), m_cat(&posix_category) {} + error_condition( int val, const error_category & cat ) : m_val(val), m_cat(&cat) {} + template + error_condition(ConditionEnum e, + typename boost::enable_if >::type* = 0) + { + *this = make_error_condition(e); + } + + // modifiers: + + void assign( int val, const error_category & cat ) + { + m_val = val; + m_cat = &cat; + } + + template + typename boost::enable_if, error_condition>::type & + operator=( ConditionEnum val ) + { + *this = make_error_condition(val); + return *this; + } + + void clear() + { + m_val = 0; + m_cat = &posix_category; + } // observers: - value_type value() const { return m_value; } - error_category category() const { return m_category; } - int to_errno() const; // name chosen to limit surprises - // see Kohlhoff Jun 28 '06 - std::string message() const; - wstring_t wmessage() const; - - void assign( value_type val, const error_category & cat ) - { - m_value = val; - m_category = cat; - } - - // relationals: - bool operator==( const error_code & rhs ) const - { - return value() == rhs.value() && category() == rhs.category(); - } - bool operator!=( const error_code & rhs ) const - { - return !(*this == rhs); - } - bool operator<( const error_code & rhs ) const - { - return category() < rhs.category() - || ( category() == rhs.category() && value() < rhs.value() ); - } - bool operator<=( const error_code & rhs ) const { return *this == rhs || *this < rhs; } - bool operator> ( const error_code & rhs ) const { return !(*this <= rhs); } - bool operator>=( const error_code & rhs ) const { return !(*this < rhs); } + int value() const { return m_val; } + const error_category & category() const { return *m_cat; } + std::string message() const { return m_cat->message(value()); } typedef void (*unspecified_bool_type)(); static void unspecified_bool_true() {} operator unspecified_bool_type() const // true if error { - return m_value == value_type() ? 0 : unspecified_bool_true; + return m_val == 0 ? 0 : unspecified_bool_true; } bool operator!() const // true if no error { - return m_value == value_type(); + return m_val == 0; } - // statics: - static error_category new_category( errno_decoder ed = 0, - message_decoder md = 0, wmessage_decoder wmd = 0 ); - static bool get_decoders( error_category cat, errno_decoder & ed, - message_decoder & md, wmessage_decoder & wmd ); + // relationals: + // the more symmetrical non-member syntax allows enum + // conversions work for both rhs and lhs. + inline friend bool operator==( const error_condition & lhs, + const error_condition & rhs ) + { + return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; + } + + inline friend bool operator<( const error_condition & lhs, + const error_condition & rhs ) + // the more symmetrical non-member syntax allows enum + // conversions work for both rhs and lhs. + { + return lhs.m_cat < rhs.m_cat + || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); + } private: - value_type m_value; - error_category m_category; + int m_val; + const error_category * m_cat; + + }; + + // class error_code ----------------------------------------------------// + + // We want error_code to be a value type that can be copied without slicing + // and without requiring heap allocation, but we also want it to have + // polymorphic behavior based on the error category. This is achieved by + // abstract base class error_category supplying the polymorphic behavior, + // and error_code containing a pointer to an object of a type derived + // from error_category. + class error_code + { + public: + + // constructors: + error_code() : m_val(0), m_cat(&system_category) {} + error_code( int val, const error_category & cat ) : m_val(val), m_cat(&cat) {} + + template + error_code(CodeEnum e, + typename boost::enable_if >::type* = 0) + { + *this = make_error_code(e); + } + + // modifiers: + void assign( int val, const error_category & cat ) + { + m_val = val; + m_cat = &cat; + } + + template + typename boost::enable_if, error_code>::type & + operator=( CodeEnum val ) + { + *this = make_error_code(val); + return *this; + } + + void clear() + { + m_val = 0; + m_cat = &system_category; + } + + // observers: + int value() const { return m_val; } + const error_category & category() const { return *m_cat; } + error_condition default_error_condition() const { return m_cat->default_error_condition(value()); } + std::string message() const { return m_cat->message(value()); } + + typedef void (*unspecified_bool_type)(); + static void unspecified_bool_true() {} + + operator unspecified_bool_type() const // true if error + { + return m_val == 0 ? 0 : unspecified_bool_true; + } + + bool operator!() const // true if no error + { + return m_val == 0; + } + + // relationals: + inline friend bool operator==( const error_code & lhs, + const error_code & rhs ) + // the more symmetrical non-member syntax allows enum + // conversions work for both rhs and lhs. + { + return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; + } + + inline friend bool operator<( const error_code & lhs, + const error_code & rhs ) + // the more symmetrical non-member syntax allows enum + // conversions work for both rhs and lhs. + { + return lhs.m_cat < rhs.m_cat + || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); + } + + private: + int m_val; + const error_category * m_cat; + }; // non-member functions ------------------------------------------------// + inline bool operator!=( const error_code & lhs, + const error_code & rhs ) + { + return !(lhs == rhs); + } + + inline bool operator!=( const error_condition & lhs, + const error_condition & rhs ) + { + return !(lhs == rhs); + } + + inline bool operator==( const error_code & code, + const error_condition & condition ) + { + return code.category().equivalent( code.value(), condition ) + || condition.category().equivalent( code, condition.value() ); + } + + inline bool operator!=( const error_code & lhs, + const error_condition & rhs ) + { + return !(lhs == rhs); + } + + inline bool operator==( const error_condition & condition, + const error_code & code ) + { + return condition.category().equivalent( code, condition.value() ) + || code.category().equivalent( code.value(), condition ); + } + + inline bool operator!=( const error_condition & lhs, + const error_code & rhs ) + { + return !(lhs == rhs); + } + + // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet. + + template + inline std::basic_ostream& + operator<< (std::basic_ostream& os, error_code ec) + { + os << ec.category().name() << ':' << ec.value(); + return os; + } + inline std::size_t hash_value( const error_code & ec ) { return static_cast(ec.value()) - + (static_cast(ec.category().value()) << 16 ); + + reinterpret_cast(&ec.category()); } + // make_* functions for posix::posix_errno -----------------------------// + + // explicit conversion: + inline error_code make_error_code( posix::posix_errno e ) + { return error_code( e, posix_category ); } + + // implicit conversion: + inline error_condition make_error_condition( posix::posix_errno e ) + { return error_condition( e, posix_category ); } + + // error_category default implementation -------------------------------// + + inline error_condition error_category::default_error_condition( int ev ) const + { + return error_condition( ev, *this ); + } + + inline bool error_category::equivalent( int code, + const error_condition & condition ) const + { + return default_error_condition( code ) == condition; + } + + inline bool error_category::equivalent( const error_code & code, + int condition ) const + { + return *this == code.category() && code.value() == condition; + } + + // error_category implementation note: VC++ 8.0 objects to name() and + // message() being pure virtual functions. Thus these implementations. + inline const char * error_category::name() const + { + return "error: should never be called"; + } + + inline std::string error_category::message( int ev ) const + { + static std::string s("error: should never be called"); + return s; + } + + // ----------------------------------------------------------------------// + + // Operating system specific interfaces --------------------------------// + + + // The interface is divided into general and system-specific portions to + // meet these requirements: + // + // * Code calling an operating system API can create an error_code with + // a single category (system_category), even for POSIX-like operating + // systems that return some POSIX errno values and some native errno + // values. This code should not have to pay the cost of distinguishing + // between categories, since it is not yet known if that is needed. + // + // * Users wishing to write system-specific code should be given enums for + // at least the common error cases. + // + // * System specific code should fail at compile time if moved to another + // operating system. + +#ifdef BOOST_POSIX_API + + // POSIX-based systems -------------------------------------------------// + + // To construct an error_code after a API error: + // + // error_code( errno, system_category ) + + // User code should use the portable "posix" enums for POSIX errors; this + // allows such code to be portable to non-POSIX systems. For the non-POSIX + // errno values that POSIX-based systems typically provide in addition to + // POSIX values, use the system specific enums below. + +# ifdef __CYGWIN__ + + namespace cygwin + { + enum cygwin_errno + { + no_net = ENONET, + no_package = ENOPKG, + no_share = ENOSHARE, + }; + } // namespace cygwin + + template<> struct is_error_code_enum + { static const bool value = true; }; + + inline error_code make_error_code(cygwin::cygwin_errno e) + { return error_code( e, system_category ); } + +# elif defined(linux) || defined(__linux) || defined(__linux__) + + namespace Linux // linux lowercase name preempted by use as predefined macro + { + enum linux_error + { + advertise_error = EADV, + bad_exchange = EBADE, + bad_file_number = EBADFD, + bad_font_format = EBFONT, + bad_request_code = EBADRQC, + bad_request_descriptor = EBADR, + bad_slot = EBADSLT, + channel_range = ECHRNG, + communication_error = ECOMM, + dot_dot_error = EDOTDOT, + exchange_full = EXFULL, + host_down = EHOSTDOWN, + is_named_file_type= EISNAM, + key_expired = EKEYEXPIRED, + key_rejected = EKEYREJECTED, + key_revoked = EKEYREVOKED, + level2_halt= EL2HLT, + level2_no_syncronized= EL2NSYNC, + level3_halt = EL3HLT, + level3_reset = EL3RST, + link_range = ELNRNG, + medium_type = EMEDIUMTYPE, + no_anode= ENOANO, + no_block_device = ENOTBLK, + no_csi = ENOCSI, + no_key = ENOKEY, + no_medium = ENOMEDIUM, + no_network = ENONET, + no_package = ENOPKG, + not_avail = ENAVAIL, + not_named_file_type= ENOTNAM, + not_recoverable = ENOTRECOVERABLE, + not_unique = ENOTUNIQ, + owner_dead = EOWNERDEAD, + protocol_no_supported = EPFNOSUPPORT, + remote_address_changed = EREMCHG, + remote_io_error = EREMOTEIO, + remote_object = EREMOTE, + restart_needed = ERESTART, + shared_library_access = ELIBACC, + shared_library_bad = ELIBBAD, + shared_library_execute = ELIBEXEC, + shared_library_max_ = ELIBMAX, + shared_library_section= ELIBSCN, + shutdown = ESHUTDOWN, + socket_type_not_supported = ESOCKTNOSUPPORT, + srmount_error = ESRMNT, + stream_pipe_error = ESTRPIPE, + too_many_references = ETOOMANYREFS, + too_many_users = EUSERS, + unattached = EUNATCH, + unclean = EUCLEAN, + }; + } // namespace Linux + + template<> struct is_error_code_enum + { static const bool value = true; }; + + inline error_code make_error_code(Linux::linux_error e) + { return error_code( e, system_category ); } + +# endif + + // TODO: Add more POSIX-based operating systems here + + +#elif defined(BOOST_WINDOWS_API) + + // Microsoft Windows ---------------------------------------------------// + + // To construct an error_code after a API error: + // + // error_code( ::GetLastError(), system_category ) + + namespace windows + { + enum windows_error + { + success = 0, + // These names and values are based on Windows winerror.h + invalid_function = ERROR_INVALID_FUNCTION, + file_not_found = ERROR_FILE_NOT_FOUND, + path_not_found = ERROR_PATH_NOT_FOUND, + too_many_open_files = ERROR_TOO_MANY_OPEN_FILES, + access_denied = ERROR_ACCESS_DENIED, + invalid_handle = ERROR_INVALID_HANDLE, + arena_trashed = ERROR_ARENA_TRASHED, + not_enough_memory = ERROR_NOT_ENOUGH_MEMORY, + invalid_block = ERROR_INVALID_BLOCK, + bad_environment = ERROR_BAD_ENVIRONMENT, + bad_format = ERROR_BAD_FORMAT, + invalid_access = ERROR_INVALID_ACCESS, + outofmemory = ERROR_OUTOFMEMORY, + invalid_drive = ERROR_INVALID_DRIVE, + current_directory = ERROR_CURRENT_DIRECTORY, + not_same_device = ERROR_NOT_SAME_DEVICE, + no_more_files = ERROR_NO_MORE_FILES, + write_protect = ERROR_WRITE_PROTECT, + bad_unit = ERROR_BAD_UNIT, + not_ready = ERROR_NOT_READY, + bad_command = ERROR_BAD_COMMAND, + crc = ERROR_CRC, + bad_length = ERROR_BAD_LENGTH, + seek = ERROR_SEEK, + not_dos_disk = ERROR_NOT_DOS_DISK, + sector_not_found = ERROR_SECTOR_NOT_FOUND, + out_of_paper = ERROR_OUT_OF_PAPER, + write_fault = ERROR_WRITE_FAULT, + read_fault = ERROR_READ_FAULT, + gen_failure = ERROR_GEN_FAILURE, + sharing_violation = ERROR_SHARING_VIOLATION, + lock_violation = ERROR_LOCK_VIOLATION, + wrong_disk = ERROR_WRONG_DISK, + sharing_buffer_exceeded = ERROR_SHARING_BUFFER_EXCEEDED, + handle_eof = ERROR_HANDLE_EOF, + handle_disk_full= ERROR_HANDLE_DISK_FULL, + rem_not_list = ERROR_REM_NOT_LIST, + dup_name = ERROR_DUP_NAME, + bad_net_path = ERROR_BAD_NETPATH, + network_busy = ERROR_NETWORK_BUSY, + // ... + file_exists = ERROR_FILE_EXISTS, + cannot_make = ERROR_CANNOT_MAKE, + // ... + broken_pipe = ERROR_BROKEN_PIPE, + open_failed = ERROR_OPEN_FAILED, + buffer_overflow = ERROR_BUFFER_OVERFLOW, + disk_full= ERROR_DISK_FULL, + // ... + lock_failed = ERROR_LOCK_FAILED, + busy = ERROR_BUSY, + cancel_violation = ERROR_CANCEL_VIOLATION, + already_exists = ERROR_ALREADY_EXISTS + // ... + + // TODO: add more Windows errors + }; + } // namespace windows + + template<> struct is_error_code_enum + { static const bool value = true; }; + + inline error_code make_error_code(windows::windows_error e) + { return error_code( e, system_category ); } + +#else +# error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined +#endif + } // namespace system } // namespace boost #include // pops abi_prefix.hpp pragmas -#endif // BOOST_SYSTEM_ERROR_CODE_HPP +# ifdef BOOST_ERROR_CODE_HEADER_ONLY +# include +# endif + +#endif // BOOST_ERROR_CODE_HPP diff --git a/include/boost/system/system_error.hpp b/include/boost/system/system_error.hpp index cb94dcf..3d39ecf 100644 --- a/include/boost/system/system_error.hpp +++ b/include/boost/system/system_error.hpp @@ -17,59 +17,52 @@ namespace boost { namespace system { - enum message_action { append_message, no_message }; - // class system_error --------------------------------------------------// class system_error : public std::runtime_error { public: - explicit system_error( error_code ec ) - : std::runtime_error(std::string()), m_error_code(ec), - m_append_message(true) {} - - system_error( error_code ec, const std::string & what_arg, - message_action ma = append_message ) - : std::runtime_error(what_arg), m_error_code(ec), - m_append_message(ma==append_message) {} - - system_error( error_code::value_type ev, error_category ecat ) - : std::runtime_error(std::string()), m_error_code(ev,ecat), - m_append_message(true) {} - - system_error( error_code::value_type ev, error_category ecat, - const std::string & what_arg, message_action ma = append_message ) - : std::runtime_error(what_arg), m_error_code(ev,ecat), - m_append_message(ma==append_message) {} + system_error( error_code ec ) + : std::runtime_error(""), m_error_code(ec) {} + system_error( error_code ec, const std::string & what_arg ) + : std::runtime_error(what_arg), m_error_code(ec) {} + system_error( int ev, const error_category & ecat, + const std::string & what_arg ) + : std::runtime_error(what_arg), m_error_code(ev,ecat) {} + system_error( int ev, const error_category & ecat ) + : std::runtime_error(""), m_error_code(ev,ecat) {} virtual ~system_error() throw() {} - const error_code & code() const throw() { return m_error_code; } - - const char * what() const throw() - // see http://www.boost.org/more/error_handling.html for lazy build rationale - { - if ( !m_error_code || !m_append_message ) return runtime_error::what(); - if ( m_what.empty() ) - { - try - { - m_what = runtime_error::what(); - if ( !m_what.empty() ) m_what += ": "; - m_what += m_error_code.message(); - } - catch (...) { return runtime_error::what(); } - } - return m_what.c_str(); - } - + const error_code & code() const throw() { return m_error_code; } + const char * what() const throw(); private: error_code m_error_code; mutable std::string m_what; - bool m_append_message; }; + // implementation ------------------------------------------------------// + + inline const char * system_error::what() const throw() + // see http://www.boost.org/more/error_handling.html for lazy build rationale + { + if ( m_what.empty() ) + { + try + { + m_what = this->runtime_error::what(); + if ( m_error_code ) + { + if ( !m_what.empty() ) m_what += ": "; + m_what += m_error_code.message(); + } + } + catch (...) { return runtime_error::what(); } + } + return m_what.c_str(); + } + } // namespace system } // namespace boost diff --git a/src/error_code.cpp b/src/error_code.cpp index 616a22e..9dd0970 100644 --- a/src/error_code.cpp +++ b/src/error_code.cpp @@ -30,15 +30,12 @@ #include using namespace boost::system; +using namespace boost::system::posix; #include // for strerror/strerror_r -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::strerror; } -# endif - # if defined( BOOST_WINDOWS_API ) -# include "windows.h" +# include # ifndef ERROR_INCORRECT_SIZE # define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS # endif @@ -49,75 +46,282 @@ using namespace boost::system; namespace { -#ifdef BOOST_WINDOWS_API - struct native_to_errno_t + struct system_to_posix_t { - boost::int32_t native_value; - int to_errno; + int system_value; + boost::system::posix::posix_errno posix_value; }; - const native_to_errno_t native_to_errno[] = + const system_to_posix_t system_to_posix[] = { + +#ifdef BOOST_POSIX_API + // POSIX-like O/S -> posix_errno decode table ----------------------------// + + // most common errors first to speed sequential search + { ENOENT, no_such_file_or_directory }, + { EACCES, permission_denied }, + { EINVAL, invalid_argument }, + + // rest are alphabetical for easy maintenance + { 0, success }, + { E2BIG, argument_list_too_long }, + { EADDRINUSE, address_in_use }, + { EADDRNOTAVAIL, address_not_available }, + { EAFNOSUPPORT, address_family_not_supported }, + { EAGAIN, resource_unavailable_try_again }, + { EALREADY, connection_already_in_progress }, + { EBADF, bad_file_descriptor }, + { EBADMSG, bad_message }, + { EBUSY, device_or_resource_busy }, + { ECANCELED, operation_canceled }, + { ECHILD, no_child_process }, + { ECONNABORTED, connection_aborted }, + { ECONNREFUSED, connection_refused }, + { ECONNRESET, connection_reset }, + { EDEADLK, resource_deadlock_would_occur }, + { EDESTADDRREQ, destination_address_required }, + { EDOM, argument_out_of_domain }, + { EEXIST, file_exists }, + { EFAULT, bad_address }, + { EFBIG, file_too_large }, + { EHOSTUNREACH, host_unreachable }, + { EIDRM, identifier_removed }, + { EILSEQ, illegal_byte_sequence }, + { EINPROGRESS, operation_in_progress }, + { EINTR, interrupted }, + { EIO, io_error }, + { EISCONN, already_connected }, + { EISDIR, is_a_directory }, + { ELOOP, too_many_synbolic_link_levels }, + { EMFILE, too_many_files_open }, + { EMLINK, too_many_links }, + { EMSGSIZE, message_size }, + { ENAMETOOLONG, filename_too_long }, + { ENETDOWN, network_down }, + { ENETRESET, network_reset }, + { ENETUNREACH, network_unreachable }, + { ENFILE, too_many_files_open_in_system }, + { ENOBUFS, no_buffer_space }, + { ENODATA, no_message_available }, + { ENODEV, no_such_device }, + { ENOEXEC, executable_format_error }, + { ENOLCK, no_lock_available }, + { ENOLINK, no_link }, + { ENOMEM, not_enough_memory }, + { ENOMSG, no_message }, + { ENOPROTOOPT, no_protocol_option }, + { ENOSPC, no_space_on_device }, + { ENOSR, no_stream_resources }, + { ENOSTR, not_a_stream }, + { ENOSYS, function_not_supported }, + { ENOTCONN, not_connected }, + { ENOTDIR, not_a_directory }, + { ENOTEMPTY, directory_not_empty }, + { ENOTRECOVERABLE, state_not_recoverable }, + { ENOTSOCK, not_a_socket }, + { ENOTSUP, not_supported }, + { ENOTTY, inappropriate_io_control_operation }, + { ENXIO, no_such_device_or_address }, + { EOPNOTSUPP, operation_not_supported }, + { EOVERFLOW, value_too_large }, + { EOWNERDEAD, owner_dead }, + { EPERM, operation_not_permitted }, + { EPIPE, broken_pipe }, + { EPROTO, protocol_error }, + { EPROTONOSUPPORT, protocol_not_supported }, + { EPROTOTYPE, wrong_protocol_type }, + { ERANGE, result_out_of_range }, + { EROFS, read_only_file_system }, + { ESPIPE, invalid_seek }, + { ESRCH, no_such_process }, + { ETIME, stream_timeout }, + { ETIMEDOUT, timed_out }, + { ETXTBSY, text_file_busy }, + { EWOULDBLOCK, operation_would_block }, + { EXDEV, cross_device_link } + +#else + + // Windows system -> posix_errno decode table ----------------------------// + // see WinError.h comments for descriptions of errors // most common errors first to speed sequential search - { ERROR_FILE_NOT_FOUND, ENOENT }, - { ERROR_PATH_NOT_FOUND, ENOENT }, + { ERROR_FILE_NOT_FOUND, no_such_file_or_directory }, + { ERROR_PATH_NOT_FOUND, no_such_file_or_directory }, // rest are alphabetical for easy maintenance - { 0, 0 }, // no error - { ERROR_ACCESS_DENIED, EACCES }, - { ERROR_ALREADY_EXISTS, EEXIST }, - { ERROR_BAD_UNIT, ENODEV }, - { ERROR_BUFFER_OVERFLOW, ENAMETOOLONG }, - { ERROR_BUSY, EBUSY }, - { ERROR_BUSY_DRIVE, EBUSY }, - { ERROR_CANNOT_MAKE, EACCES }, - { ERROR_CANTOPEN, EIO }, - { ERROR_CANTREAD, EIO }, - { ERROR_CANTWRITE, EIO }, - { ERROR_CURRENT_DIRECTORY, EACCES }, - { ERROR_DEV_NOT_EXIST, ENODEV }, - { ERROR_DEVICE_IN_USE, EBUSY }, - { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, - { ERROR_DIRECTORY, EINVAL }, // WinError.h: "The directory name is invalid" - { ERROR_DISK_FULL, ENOSPC }, - { ERROR_FILE_EXISTS, EEXIST }, - { ERROR_HANDLE_DISK_FULL, ENOSPC }, - { ERROR_INVALID_ACCESS, EACCES }, - { ERROR_INVALID_DRIVE, ENODEV }, - { ERROR_INVALID_FUNCTION, ENOSYS }, - { ERROR_INVALID_HANDLE, EBADHANDLE }, - { ERROR_INVALID_NAME, EINVAL }, - { ERROR_LOCK_VIOLATION, EACCES }, - { ERROR_LOCKED, EACCES }, - { ERROR_NEGATIVE_SEEK, EINVAL }, - { ERROR_NOACCESS, EACCES }, - { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, - { ERROR_NOT_READY, EAGAIN }, - { ERROR_NOT_SAME_DEVICE, EXDEV }, - { ERROR_OPEN_FAILED, EIO }, - { ERROR_OPEN_FILES, EBUSY }, - { ERROR_OUTOFMEMORY, ENOMEM }, - { ERROR_READ_FAULT, EIO }, - { ERROR_SEEK, EIO }, - { ERROR_SHARING_VIOLATION, EACCES }, - { ERROR_TOO_MANY_OPEN_FILES, ENFILE }, - { ERROR_WRITE_FAULT, EIO }, - { ERROR_WRITE_PROTECT, EROFS } + { 0, success }, + { ERROR_ACCESS_DENIED, permission_denied }, + { ERROR_ALREADY_EXISTS, file_exists }, + { ERROR_BAD_UNIT, no_such_device }, + { ERROR_BUFFER_OVERFLOW, filename_too_long }, + { ERROR_BUSY, device_or_resource_busy }, + { ERROR_BUSY_DRIVE, device_or_resource_busy }, + { ERROR_CANNOT_MAKE, permission_denied }, + { ERROR_CANTOPEN, io_error }, + { ERROR_CANTREAD, io_error }, + { ERROR_CANTWRITE, io_error }, + { ERROR_CURRENT_DIRECTORY, permission_denied }, + { ERROR_DEV_NOT_EXIST, no_such_device }, + { ERROR_DEVICE_IN_USE, device_or_resource_busy }, + { ERROR_DIR_NOT_EMPTY, directory_not_empty }, + { ERROR_DIRECTORY, invalid_argument }, // WinError.h: "The directory name is invalid" + { ERROR_DISK_FULL, no_space_on_device }, + { ERROR_FILE_EXISTS, file_exists }, + { ERROR_HANDLE_DISK_FULL, no_space_on_device }, + { ERROR_INVALID_ACCESS, permission_denied }, + { ERROR_INVALID_DRIVE, no_such_device }, + { ERROR_INVALID_FUNCTION, function_not_supported }, + { ERROR_INVALID_HANDLE, invalid_argument }, + { ERROR_INVALID_NAME, invalid_argument }, + { ERROR_LOCK_VIOLATION, no_lock_available }, + { ERROR_LOCKED, no_lock_available }, + { ERROR_NEGATIVE_SEEK, invalid_argument }, + { ERROR_NOACCESS, permission_denied }, + { ERROR_NOT_ENOUGH_MEMORY, not_enough_memory }, + { ERROR_NOT_READY, resource_unavailable_try_again }, + { ERROR_NOT_SAME_DEVICE, cross_device_link }, + { ERROR_OPEN_FAILED, io_error }, + { ERROR_OPEN_FILES, device_or_resource_busy }, + { ERROR_OUTOFMEMORY, not_enough_memory }, + { ERROR_READ_FAULT, io_error }, + { ERROR_SEEK, io_error }, + { ERROR_SHARING_VIOLATION, permission_denied }, + { ERROR_TOO_MANY_OPEN_FILES, too_many_files_open }, + { ERROR_WRITE_FAULT, io_error }, + { ERROR_WRITE_PROTECT, permission_denied } + +#endif }; - int windows_ed( const error_code & ec ) + // standard error categories -------------------------------------------// + + class posix_error_category : public error_category { - const native_to_errno_t * cur = native_to_errno; - do - { - if ( ec.value() == cur->native_value ) return cur->to_errno; - ++cur; - } while ( cur != native_to_errno + sizeof(native_to_errno)/sizeof(native_to_errno_t) ); - return EOTHER; + public: + const char * name() const; + std::string message( int ev ) const; + }; + + class system_error_category : public error_category + { + public: + const char * name() const; + posix::posix_errno posix( int ev ) const; + std::string message( int ev ) const; + error_condition default_error_condition( int ev ) const; + }; + + const posix_error_category posix_category_const; + const system_error_category system_category_const; + + // posix_error_category implementation ---------------------------------// + + const char * posix_error_category::name() const + { + return "POSIX"; } + std::string posix_error_category::message( int ev ) const + { + // strerror_r is preferred because it is always thread safe, + // however, we fallback to strerror in certain cases because: + // -- Windows doesn't provide strerror_r. + // -- HP and Sundo provide strerror_r on newer systems, but there is + // no way to tell if is available at runtime and in any case their + // versions of strerror are thread safe anyhow. + // -- Linux only sometimes provides strerror_r. + // -- Tru64 provides strerror_r only when compiled -pthread. + // -- VMS doesn't provide strerror_r, but on this platform, strerror is + // thread safe. + # if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\ + || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\ + || (defined(__osf__) && !defined(_REENTRANT))\ + || (defined(__vms)) + const char * c_str = std::strerror( ev ); + return std::string( c_str ? c_str : "invalid_argument" ); + # else + char buf[64]; + char * bp = buf; + std::size_t sz = sizeof(buf); + # if defined(__CYGWIN__) || defined(__USE_GNU) + // Oddball version of strerror_r + const char * c_str = strerror_r( ev, bp, sz ); + return std::string( c_str ? c_str : "invalid_argument" ); + # else + // POSIX version of strerror_r + int result; + for (;;) + { + // strerror_r returns 0 on success, otherwise ERANGE if buffer too small, + // invalid_argument if ev not a valid error number + if ( (result = strerror_r( ev, bp, sz )) == 0 ) + break; + else + { + # if defined(__linux) + // Linux strerror_r returns -1 on error, with error number in errno + result = errno; + # endif + if ( result != ERANGE ) break; + if ( sz > sizeof(buf) ) std::free( bp ); + sz *= 2; + if ( (bp = static_cast(std::malloc( sz ))) == 0 ) + return std::string( "ENOMEM" ); + } + } + try + { + std::string msg( ( result == invalid_argument ) ? "invalid_argument" : bp ); + if ( sz > sizeof(buf) ) std::free( bp ); + sz = 0; + return msg; + } + catch(...) + { + if ( sz > sizeof(buf) ) std::free( bp ); + throw; + } + # endif + # endif + } + // system_error_category implementation --------------------------------// + + const char * system_error_category::name() const + { + return "system"; + } + + posix_errno system_error_category::posix( int ev ) const + { + const system_to_posix_t * cur = system_to_posix; + do + { + if ( ev == cur->system_value ) + return cur->posix_value; + ++cur; + } while ( cur != system_to_posix + + sizeof(system_to_posix)/sizeof(system_to_posix_t) ); + return static_cast(-1); + } + + error_condition system_error_category::default_error_condition( int ev ) const + { + int tmp = posix(ev); + return tmp >= 0 + ? error_condition( tmp, posix_category ) + : error_condition( ev, system_category ); + } + +# if !defined( BOOST_WINDOWS_API ) + + std::string system_error_category::message( int ev ) const + { + return posix_category.message( ev ); + } +# else // TODO: //Some quick notes on the implementation (sorry for the noise if @@ -133,8 +337,7 @@ namespace // //Cheers, //Chris - - std::string windows_md( const error_code & ec ) + std::string system_error_category::message( int ev ) const { LPVOID lpMsgBuf; ::FormatMessageA( @@ -142,7 +345,7 @@ namespace FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - ec.value(), + ev, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPSTR) &lpMsgBuf, 0, @@ -153,185 +356,31 @@ namespace while ( str.size() && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) str.erase( str.size()-1 ); + if ( str.size() && str[str.size()-1] == '.' ) + { str.erase( str.size()-1 ); } return str; } - - wstring_t windows_wmd( const error_code & ec ) - { - LPVOID lpMsgBuf; - ::FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - ec.value(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPWSTR) &lpMsgBuf, - 0, - NULL - ); - wstring_t str( static_cast(lpMsgBuf) ); - ::LocalFree( lpMsgBuf ); // free the buffer - while ( str.size() - && (str[str.size()-1] == L'\n' || str[str.size()-1] == L'\r') ) - str.erase( str.size()-1 ); - return str; - } - -#endif - - int errno_ed( const error_code & ec ) { return ec.value(); } - - std::string errno_md( const error_code & ec ) - { - // strerror_r is preferred because it is always thread safe, - // however, we fallback to strerror in certain cases because: - // -- Windows doesn't provide strerror_r. - // -- HP and Sundo provide strerror_r on newer systems, but there is - // no way to tell if is available at runtime and in any case their - // versions of strerror are thread safe anyhow. - // -- Linux only sometimes provides strerror_r. - // -- Tru64 provides strerror_r only when compiled -pthread. - // -- VMS doesn't provide strerror_r, but on this platform, strerror is - // thread safe. -# if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\ - || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\ - || (defined(__osf__) && !defined(_REENTRANT))\ - || (defined(__vms)) - const char * c_str = std::strerror( ec.value() ); - return std::string( c_str ? c_str : "EINVAL" ); -# else - char buf[64]; - char * bp = buf; - std::size_t sz = sizeof(buf); -# if defined(__CYGWIN__) || defined(__USE_GNU) - // Oddball version of strerror_r - const char * c_str = strerror_r( ec.value(), bp, sz ); - return std::string( c_str ? c_str : "EINVAL" ); -# else - // POSIX version of strerror_r - int result; - for (;;) - { - // strerror_r returns 0 on success, otherwise ERANGE if buffer too small, - // EINVAL if ec.value() not a valid error number - if ( (result = strerror_r( ec.value(), bp, sz )) == 0 ) - break; - else - { -# if defined(__linux) - // Linux strerror_r returns -1 on error, with error number in errno - result = errno; -# endif - if ( result != ERANGE ) break; - if ( sz > sizeof(buf) ) std::free( bp ); - sz *= 2; - if ( (bp = static_cast(std::malloc( sz ))) == 0 ) - return std::string( "ENOMEM" ); - } - } - try - { - std::string msg( ( result == EINVAL ) ? "EINVAL" : bp ); - if ( sz > sizeof(buf) ) std::free( bp ); - sz = 0; - return msg; - } - catch(...) - { - if ( sz > sizeof(buf) ) std::free( bp ); - throw; - } -# endif # endif - } - wstring_t errno_wmd( const error_code & ec ) - { - // TODO: Implement this: - assert( 0 && "sorry, not implemented yet" ); - wstring_t str; - return str; - } - - struct decoder_element - { - errno_decoder ed; - message_decoder md; - wmessage_decoder wmd; - - decoder_element( errno_decoder ed_, - message_decoder md_, wmessage_decoder wmd_ ) - : ed(ed_), md(md_), wmd(wmd_) {} - - decoder_element() : ed(0), md(0), wmd(0) {} - }; - - typedef std::vector< decoder_element > decoder_vec_type; - - decoder_vec_type & decoder_vec() - { - static const decoder_element init_decoders[] = -#ifdef BOOST_WINDOWS_API - { decoder_element( errno_ed, errno_md, errno_wmd ), - decoder_element( windows_ed, windows_md, windows_wmd) }; -#else - { decoder_element( errno_ed, errno_md, errno_wmd ) }; -#endif - - static decoder_vec_type dv( init_decoders, - init_decoders + sizeof(init_decoders)/sizeof(decoder_element)); - return dv; - } } // unnamed namespace namespace boost { namespace system { - error_category error_code::new_category( - errno_decoder ed, message_decoder md, wmessage_decoder wmd ) - { - decoder_vec().push_back( decoder_element( ed, md, wmd ) ); - return error_category( static_cast(decoder_vec().size()) - 1 ); - } - bool error_code::get_decoders( error_category cat, - errno_decoder & ed, message_decoder & md, wmessage_decoder & wmd ) - { - if ( cat.value() < decoder_vec().size() ) - { - ed = decoder_vec()[cat.value()].ed; - md = decoder_vec()[cat.value()].md; - wmd = decoder_vec()[cat.value()].wmd; - return true; - } - return false; - } + BOOST_SYSTEM_DECL const error_category & posix_category + = posix_category_const; - int error_code::to_errno() const - { - return (m_category.value() < decoder_vec().size() - && decoder_vec()[m_category.value()].ed) - ? decoder_vec()[m_category.value()].ed( *this ) - : EOTHER; - } + BOOST_SYSTEM_DECL const error_category & system_category + = system_category_const; - std::string error_code::message() const - { - return (m_category.value() < decoder_vec().size() - && decoder_vec()[m_category.value()].md) - ? decoder_vec()[m_category.value()].md( *this ) - : std::string( "API error" ); - } + // deprecated synonyms + BOOST_SYSTEM_DECL const error_category & errno_ecat + = posix_category_const; - wstring_t error_code::wmessage() const - { - return (m_category.value() < decoder_vec().size() - && decoder_vec()[m_category.value()].wmd) - ? decoder_vec()[m_category.value()].wmd( *this ) - : wstring_t( L"API error" ); - } + BOOST_SYSTEM_DECL const error_category & native_ecat + = system_category_const; } // namespace system } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e18d938..2aa6899 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -38,4 +38,7 @@ project : : : BOOST_SYSTEM_DYN_LINK : system_error_test_dll ] + [ run header_only_test.cpp + : : : static static + ] ; diff --git a/test/error_code_test.cpp b/test/error_code_test.cpp index f7e73e6..35149f4 100644 --- a/test/error_code_test.cpp +++ b/test/error_code_test.cpp @@ -10,7 +10,7 @@ //----------------------------------------------------------------------------// // VC++ 8.0 warns on usage of certain Standard Library and API functions that -// can be cause buffer overruns or other possible security issues if misused. +// can cause buffer overruns or other possible security issues if misused. // See http://msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC/default.aspx // But the wording of the warning is misleading and unsettling, there are no // portable alternative functions, and VC++ 8.0's own libraries use the @@ -20,6 +20,11 @@ #include #include +#include +#include +#include +#include +#include // Although using directives are not the best programming practice, testing // with a boost::system using directive increases use scenario coverage. @@ -27,86 +32,175 @@ using namespace boost::system; # if defined( BOOST_WINDOWS_API ) # include "winerror.h" -# include +# define BOOST_ACCESS_ERROR_MACRO ERROR_ACCESS_DENIED +# elif defined( BOOST_POSIX_API ) +# define BOOST_ACCESS_ERROR_MACRO EACCES +# else +# error "Only supported for POSIX and Windows" # endif +namespace +{ + void check_ostream( error_code ec, const char * expected ) + { + std::stringstream ss; + std::string s; + + ss << ec; + ss >> s; + BOOST_CHECK( s == expected ); + } +} + // test_main ---------------------------------------------------------------// -// TODO: supply a build jam file -// TODO: supply a test jam file -// TODO: same for bjam v2 -// TODO: add message decoder tests +// TODO: add hash_value tests int test_main( int, char ** ) { - error_code ec; - error_code ec_0_native( 0, native_ecat ); - error_code ec_0_errno( 0, errno_ecat ); - error_code ec_1_native( 1, native_ecat ); - error_code ec_1_errno( 1, errno_ecat ); + std::cout << "General tests...\n"; + // unit tests: + + BOOST_CHECK( posix_category == posix_category ); + BOOST_CHECK( system_category == system_category ); + BOOST_CHECK( posix_category != system_category ); + BOOST_CHECK( system_category != posix_category ); + BOOST_CHECK( posix_category < system_category ); + BOOST_CHECK( !(system_category < posix_category) ); + + error_code ec; + error_condition dec; BOOST_CHECK( !ec ); BOOST_CHECK( ec.value() == 0 ); - BOOST_CHECK( ec.to_errno() == 0 ); + dec = ec.default_error_condition(); + BOOST_CHECK( dec.value() == 0 ); + BOOST_CHECK( dec.category() == posix_category ); + BOOST_CHECK( ec == posix::success ); + BOOST_CHECK( ec.category() == system_category ); + BOOST_CHECK( std::strcmp( ec.category().name(), "system") == 0 ); + BOOST_CHECK( !(ec < error_code( 0, system_category )) ); + BOOST_CHECK( !(error_code( 0, system_category ) < ec) ); + BOOST_CHECK( ec < error_code( 1, system_category ) ); + BOOST_CHECK( !(error_code( 1, system_category ) < ec) ); - BOOST_CHECK( !ec_0_native ); - BOOST_CHECK( ec_0_native.value() == 0 ); - BOOST_CHECK( ec_0_native.to_errno() == 0 ); + error_code ec_0_system( 0, system_category ); + BOOST_CHECK( !ec_0_system ); + BOOST_CHECK( ec_0_system.value() == 0 ); + dec = ec_0_system.default_error_condition(); + BOOST_CHECK( dec.value() == 0 ); + BOOST_CHECK( dec.category() == posix_category ); + BOOST_CHECK( ec_0_system == posix::success ); + BOOST_CHECK( ec_0_system.category() == system_category ); + BOOST_CHECK( std::strcmp( ec_0_system.category().name(), "system") == 0 ); + check_ostream( ec_0_system, "system:0" ); - BOOST_CHECK( !ec_0_errno ); - BOOST_CHECK( ec_0_errno.value() == 0 ); - BOOST_CHECK( ec_0_errno.to_errno() == 0 ); - BOOST_CHECK( ec == ec_0_errno ); - BOOST_CHECK( native_ecat != errno_ecat || ec_0_native == ec_0_errno ); - BOOST_CHECK( native_ecat == errno_ecat || ec_0_native != ec_0_errno ); + BOOST_CHECK( ec_0_system == ec ); - BOOST_CHECK( ec_1_native ); - BOOST_CHECK( ec_1_native.value() == 1 ); - BOOST_CHECK( ec_1_native.value() != 0 ); - BOOST_CHECK( ec_1_native.to_errno() != 0 ); - BOOST_CHECK( ec != ec_1_native ); - BOOST_CHECK( ec_0_native != ec_1_native ); - BOOST_CHECK( ec_0_errno != ec_1_native ); + error_code ec_1_system( 1, system_category ); + BOOST_CHECK( ec_1_system ); + BOOST_CHECK( ec_1_system.value() == 1 ); + BOOST_CHECK( ec_1_system.value() != 0 ); + BOOST_CHECK( ec != ec_1_system ); + BOOST_CHECK( ec_0_system != ec_1_system ); + check_ostream( ec_1_system, "system:1" ); - BOOST_CHECK( ec_1_errno ); - BOOST_CHECK( ec_1_errno.value() == 1 ); - BOOST_CHECK( ec_1_errno.to_errno() == 1 ); - BOOST_CHECK( ec_1_errno.to_errno() != 0 ); - BOOST_CHECK( ec != ec_1_errno ); - BOOST_CHECK( ec_0_native != ec_1_errno ); - BOOST_CHECK( ec_0_errno != ec_1_errno ); + ec = error_code( BOOST_ACCESS_ERROR_MACRO, system_category ); + BOOST_CHECK( ec ); + BOOST_CHECK( ec.value() == BOOST_ACCESS_ERROR_MACRO ); + dec = ec.default_error_condition(); + BOOST_CHECK( dec.value() == static_cast(posix::permission_denied) ); + BOOST_CHECK( dec.category() == posix_category ); + BOOST_CHECK( dec == error_condition( posix::permission_denied, posix_category ) ); + BOOST_CHECK( dec == posix::permission_denied ); + BOOST_CHECK( posix::permission_denied == dec ); + BOOST_CHECK( ec == posix::permission_denied ); + BOOST_CHECK( ec.category() == system_category ); + BOOST_CHECK( std::strcmp( ec.category().name(), "system") == 0 ); + + // test the explicit make_error_code conversion for posix + ec = make_error_code( posix::bad_message ); + BOOST_CHECK( ec ); + BOOST_CHECK( ec == posix::bad_message ); + BOOST_CHECK( posix::bad_message == ec ); + BOOST_CHECK( ec != posix::permission_denied ); + BOOST_CHECK( posix::permission_denied != ec ); + BOOST_CHECK( ec.category() == posix_category ); + + // test the deprecated predefined error_category synonyms + BOOST_CHECK( &system_category == &native_ecat ); + BOOST_CHECK( &posix_category == &errno_ecat ); + BOOST_CHECK( system_category == native_ecat ); + BOOST_CHECK( posix_category == errno_ecat ); #ifdef BOOST_WINDOWS_API - BOOST_CHECK( ec != ec_0_native ); - - // these tests probe the Windows to_errno decoder + std::cout << "Windows tests...\n"; + // these tests probe the Windows posix decoder // test the first entry in the decoder table: - ec = error_code( ERROR_FILE_NOT_FOUND, native_ecat ); + ec = error_code( ERROR_FILE_NOT_FOUND, system_category ); BOOST_CHECK( ec.value() == ERROR_FILE_NOT_FOUND ); - BOOST_CHECK( ec.to_errno() == ENOENT ); + BOOST_CHECK( ec == posix::no_such_file_or_directory ); + BOOST_CHECK( ec.default_error_condition().value() == posix::no_such_file_or_directory ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); // test the second entry in the decoder table: - ec = error_code( ERROR_PATH_NOT_FOUND, native_ecat ); + ec = error_code( ERROR_PATH_NOT_FOUND, system_category ); BOOST_CHECK( ec.value() == ERROR_PATH_NOT_FOUND ); - BOOST_CHECK( ec.to_errno() == ENOENT ); + BOOST_CHECK( ec == posix::no_such_file_or_directory ); + BOOST_CHECK( ec.default_error_condition().value() == posix::no_such_file_or_directory ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); // test the third entry in the decoder table: - ec = error_code( ERROR_ACCESS_DENIED, native_ecat ); + ec = error_code( ERROR_ACCESS_DENIED, system_category ); BOOST_CHECK( ec.value() == ERROR_ACCESS_DENIED ); - BOOST_CHECK( ec.to_errno() == EACCES ); + BOOST_CHECK( ec == posix::permission_denied ); + BOOST_CHECK( ec.default_error_condition().value() == posix::permission_denied ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); // test the last regular entry in the decoder table: - ec = error_code( ERROR_WRITE_PROTECT, native_ecat ); + ec = error_code( ERROR_WRITE_PROTECT, system_category ); BOOST_CHECK( ec.value() == ERROR_WRITE_PROTECT ); - BOOST_CHECK( ec.to_errno() == EROFS ); + BOOST_CHECK( ec == posix::permission_denied ); + BOOST_CHECK( ec.default_error_condition().value() == posix::permission_denied ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); // test not-in-table condition: - ec = error_code( 1234567890, native_ecat ); + ec = error_code( 1234567890, system_category ); BOOST_CHECK( ec.value() == 1234567890 ); - BOOST_CHECK( ec.to_errno() == EOTHER ); + BOOST_CHECK( ec.default_error_condition().value() == 1234567890 ); + BOOST_CHECK( ec.default_error_condition().category() == system_category ); + +#else // POSIX + + std::cout << "POSIX tests...\n"; + ec = error_code( EACCES, system_category ); + BOOST_CHECK( ec == error_code( posix::permission_denied, system_category ) ); + BOOST_CHECK( error_code( posix::permission_denied, system_category ) == ec ); + BOOST_CHECK( ec == posix::permission_denied ); + BOOST_CHECK( posix::permission_denied == ec ); + BOOST_CHECK( ec.default_error_condition().value() == posix::permission_denied ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); + +# ifdef __CYGWIN__ + + std::cout << "Cygwin tests...\n"; + ec = cygwin::no_package; + BOOST_CHECK( ec == cygwin::no_package ); + BOOST_CHECK( ec == error_code( ENOPKG, system_category ) ); + BOOST_CHECK( ec == error_code( cygwin::no_package, system_category ) ); + BOOST_CHECK( ec.default_error_condition().category() == system_category ); + +# elif defined(linux) || defined(__linux) || defined(__linux__) + + std::cout << "Linux tests...\n"; + ec = Linux::dot_dot_error; + BOOST_CHECK( ec == Linux::dot_dot_error ); + BOOST_CHECK( ec == error_code( EDOTDOT, system_category ) ); + BOOST_CHECK( ec == error_code( Linux::dot_dot_error, system_category ) ); + BOOST_CHECK( ec.default_error_condition().category() == posix_category ); + +# endif -#else - BOOST_CHECK( ec == ec_0_native ); #endif return 0; diff --git a/test/error_code_user_test.cpp b/test/error_code_user_test.cpp index a61caf2..ab23217 100644 --- a/test/error_code_user_test.cpp +++ b/test/error_code_user_test.cpp @@ -8,85 +8,384 @@ // See library home page at http://www.boost.org/libs/system // ------------------------------------------------------------------------ // -// This code demonstrates creation and use of a new category of error codes. -// The motivation was a Boost posting by Christopher Kohlhoff on June 28, 2006. +// This program demonstrates creation and use of new categories of error +// codes. Several scenarios are demonstrated and tested. + +// Motivation was a Boost posting by Christopher Kohlhoff on June 28, 2006. #include #include - -// ------------------------------------------------------------------------ // - -// header asio.hpp - -#define BOO_BOO 12345 // this could also be a constant; a macro is used for - // illustration because many older API's define errors - // via macro. -namespace boost -{ - namespace asio - { - // asio declares have its own error_category: - extern system::error_category asio_error; - - namespace error - { - extern boost::system::error_code boo_boo; - } - - void boo_boo( boost::system::error_code & ec ); - } -} - -// ------------------------------------------------------------------------ // - -// implementation file asio.cpp: - -namespace boost -{ - namespace asio - { - - system::error_category asio_error = system::error_code::new_category(); - - namespace error - { - boost::system::error_code boo_boo( BOO_BOO, asio_error ); - } - - // function sets ec arg to boo_boo - void boo_boo( boost::system::error_code & ec ) - { - ec = error::boo_boo; - } - } -} - -// ------------------------------------------------------------------------ // - -// a user program: - - -// #include +#include +#include #include +#ifdef BOOST_POSIX_API +# include +#else +# include +#endif + +// ------------------------------------------------------------------------ // + +// Library 1: User function passes through an error code from the +// operating system. + + +boost::system::error_code my_mkdir( const std::string & path ) +{ + return boost::system::error_code( +# ifdef BOOST_POSIX_API + ::mkdir( path.c_str(), S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH ) == 0 ? 0 : errno, +# else + ::CreateDirectoryA( path.c_str(), 0 ) != 0 ? 0 : ::GetLastError(), +# endif + boost::system::system_category ); +} + +// ------------------------------------------------------------------------ // + +// Library 2: User function passes through errno from the C-runtime. + +#include + +boost::system::error_code my_remove( const std::string & path ) +{ + return boost::system::error_code( + ::remove( path.c_str() ) == 0 ? 0 : errno, + boost::system::posix_category ); // OK for both Windows and POSIX + // Alternatively, could use posix_category + // on Windows and system_category on + // POSIX-based systems. +} + +// ------------------------------------------------------------------------ // + +// Library 3: Library uses enum to identify library specific errors. + +// This particular example is for a library within the parent namespace. For +// an example of a library not within the parent namespace, see library 4. + +// header lib3.hpp: + +namespace boost +{ + namespace lib3 + { + // lib3 has its own error_category: + extern const boost::system::error_category & lib3_error_category; + + enum error + { + boo_boo=123, + big_boo_boo + }; + + } + + namespace system + { + template<> struct is_error_code_enum + { static const bool value = true; }; + + inline error_code make_error_code(boost::lib3::error e) + { return error_code(e,boost::lib3::lib3_error_category); } + } + +} + +// implementation file lib3.cpp: + +// #include + +namespace boost +{ + namespace lib3 + { + class lib3_error_category_imp : public boost::system::error_category + { + public: + const char * name() const + { + return "lib3"; + } + + boost::system::error_condition default_error_condition( int ev ) const + { + return ev == boo_boo + ? boost::system::error_condition( boost::system::posix::io_error, + boost::system::posix_category ) + : boost::system::error_condition( ev, + boost::lib3::lib3_error_category ); + } + + std::string message( int ev ) const + { + if ( ev == boo_boo ) return std::string("boo boo"); + if ( ev == big_boo_boo ) return std::string("big boo boo"); + return std::string("unknown error"); + } + }; + + const lib3_error_category_imp lib3_error_category_const; + + const boost::system::error_category & lib3_error_category + = lib3_error_category_const; + } +} + +// ------------------------------------------------------------------------ // + +// Library 4: Library uses const error_code's to identify library specific +// errors. + +// This particular example is for a library not within the parent namespace. +// For an example of a library within the parent namespace, see library 3. + +// header lib4.hpp: + +namespace lib4 +{ + // lib4 has its own error_category: + extern const boost::system::error_category & lib4_error_category; + + extern const boost::system::error_code boo_boo; + extern const boost::system::error_code big_boo_boo; +} + +// implementation file lib4.cpp: + +// #include + +namespace lib4 +{ + class lib4_error_category_imp : public boost::system::error_category + { + public: + const char * name() const + { + return "lib4"; + } + + boost::system::error_condition default_error_condition( int ev ) const + { + return ev == boo_boo.value() + ? boost::system::error_condition( boost::system::posix::io_error, + boost::system::posix_category ) + : boost::system::error_condition( ev, lib4::lib4_error_category ); + } + + std::string message( int ev ) const + { + if ( ev == boo_boo.value() ) return std::string("boo boo"); + if ( ev == big_boo_boo.value() ) return std::string("big boo boo"); + return std::string("unknown error"); + } + }; + + const lib4_error_category_imp lib4_error_category_const; + + const boost::system::error_category & lib4_error_category + = lib4_error_category_const; + + const boost::system::error_code boo_boo( 456, lib4_error_category ); + const boost::system::error_code big_boo_boo( 789, lib4_error_category ); + +} + +// ------------------------------------------------------------------------ // + +// Chris Kolhoff's Test3, modified to work with error_code.hpp + +// Test3 +// ===== +// Define error classes to check for success, permission_denied and +// out_of_memory, but add additional mappings for a user-defined error category. +// + +//namespace test3 { + +// enum user_err +// { +// user_success = 0, +// user_permission_denied, +// user_out_of_memory +// }; +// +// class user_error_category_imp : public boost::system::error_category +// { +// public: +// const std::string & name() const +// { +// static std::string s( "test3" ); +// return s; +// } +// +// boost::system::error_code portable_error_code( int ev ) const +// { +// switch (ev) +// { +// case user_success: +// return boost::system::error_code(boost::system::posix::success, boost::system::posix_category); +// case user_permission_denied: +// return boost::system::error_code(boost::system::posix::permission_denied, boost::system::posix_category); +// case user_out_of_memory: +// return boost::system::error_code(boost::system::posix::not_enough_memory, boost::system::posix_category); +// default: +// break; +// } +// return boost::system::error_code(boost::system::posix::no_posix_equivalent, boost::system::posix_category); +// } +// +// }; +// +// const user_error_category_imp user_error_category_const; +// +// const boost::system::error_category & user_error_category +// = user_error_category_const; +// +// inline boost::system::error_code make_error_code(user_err e) +// { +// return boost::system::error_code(e, user_error_category); +// } +// +// // test code +// +// void check_success(const boost::system::error_code& ec, bool expect) +// { +// BOOST_CHECK( (ec == boost::system::posix::success) == expect ); +// if (ec == boost::system::posix::success) +// std::cout << "yes... " << (expect ? "ok" : "fail") << '\n'; +// else +// std::cout << "no... " << (expect ? "fail" : "ok") << '\n'; +// } +// +// void check_permission_denied(const boost::system::error_code& ec, bool expect) +// { +// BOOST_CHECK( (ec == boost::system::posix::permission_denied) == expect ); +// if (ec == boost::system::posix::permission_denied) +// std::cout << "yes... " << (expect ? "ok" : "fail") << '\n'; +// else +// std::cout << "no... " << (expect ? "fail" : "ok") << '\n'; +// } +// +// void check_out_of_memory(const boost::system::error_code& ec, bool expect) +// { +// BOOST_CHECK( (ec == boost::system::posix::not_enough_memory) == expect ); +// if (ec == boost::system::posix::not_enough_memory) +// std::cout << "yes... " << (expect ? "ok" : "fail") << '\n'; +// else +// std::cout << "no... " << (expect ? "fail" : "ok") << '\n'; +// } +// +// void run() +// { +// printf("Test3\n"); +// printf("=====\n"); +// boost::system::error_code ec; +// check_success(ec, true); +// check_success(boost::system::posix::success, true); +// check_success(boost::system::posix::permission_denied, false); +// check_success(boost::system::posix::not_enough_memory, false); +// check_success(user_success, true); +// check_success(user_permission_denied, false); +// check_success(user_out_of_memory, false); +// check_permission_denied(ec, false); +// check_permission_denied(boost::system::posix::success, false); +// check_permission_denied(boost::system::posix::permission_denied, true); +// check_permission_denied(boost::system::posix::not_enough_memory, false); +// check_permission_denied(user_success, false); +// check_permission_denied(user_permission_denied, true); +// check_permission_denied(user_out_of_memory, false); +// check_out_of_memory(ec, false); +// check_out_of_memory(boost::system::posix::success, false); +// check_out_of_memory(boost::system::posix::permission_denied, false); +// check_out_of_memory(boost::system::posix::not_enough_memory, true); +// check_out_of_memory(user_success, false); +// check_out_of_memory(user_permission_denied, false); +// check_out_of_memory(user_out_of_memory, true); +// +//# ifdef BOOST_WINDOWS_API +// check_success(boost::system::windows::success, true); +// check_success(boost::system::windows::access_denied, false); +// check_success(boost::system::windows::not_enough_memory, false); +// check_permission_denied(boost::system::windows::success, false); +// check_permission_denied(boost::system::windows::access_denied, true); +// check_permission_denied(boost::system::windows::not_enough_memory, false); +// check_out_of_memory(boost::system::windows::success, false); +// check_out_of_memory(boost::system::windows::access_denied, false); +// check_out_of_memory(boost::system::windows::not_enough_memory, true); +//# endif +// +// printf("\n"); +// } +// +//} // namespace test3 + + + +// ------------------------------------------------------------------------ // + int test_main( int, char *[] ) { boost::system::error_code ec; - boost::asio::boo_boo( ec ); + + // Library 1 tests: + + ec = my_mkdir( "/no-such-file-or-directory/will-not-succeed" ); + std::cout << "ec.value() is " << ec.value() << '\n'; BOOST_CHECK( ec ); - BOOST_CHECK( ec == boost::asio::error::boo_boo ); - BOOST_CHECK( ec.value() == BOO_BOO ); - BOOST_CHECK( ec.category() == boost::asio::asio_error ); + BOOST_CHECK( ec == boost::system::posix::no_such_file_or_directory ); + BOOST_CHECK( ec.category() == boost::system::system_category ); - // a real user can't rely on the value of an error_category object's value, - // but in this test program that value is known, so test for it. - BOOST_CHECK( ec.category().value() == boost::system::native_ecat.value()+1 ); + // Library 2 tests: + + ec = my_remove( "/no-such-file-or-directory" ); + std::cout << "ec.value() is " << ec.value() << '\n'; + + BOOST_CHECK( ec ); + BOOST_CHECK( ec == boost::system::posix::no_such_file_or_directory ); + BOOST_CHECK( ec.category() == boost::system::posix_category ); + + // Library 3 tests: + + ec = boost::lib3::boo_boo; + std::cout << "ec.value() is " << ec.value() << '\n'; + + BOOST_CHECK( ec ); + BOOST_CHECK( ec == boost::lib3::boo_boo ); + BOOST_CHECK( ec.value() == boost::lib3::boo_boo ); + BOOST_CHECK( ec.category() == boost::lib3::lib3_error_category ); + + BOOST_CHECK( ec == boost::system::posix::io_error ); + + boost::system::error_code ec3( boost::lib3::boo_boo+100, + boost::lib3::lib3_error_category ); + BOOST_CHECK( ec3.category() == boost::lib3::lib3_error_category ); + BOOST_CHECK( ec3.default_error_condition().category() + == boost::lib3::lib3_error_category ); + + // Library 4 tests: + + ec = lib4::boo_boo; + std::cout << "ec.value() is " << ec.value() << '\n'; + + BOOST_CHECK( ec ); + BOOST_CHECK( ec == lib4::boo_boo ); + BOOST_CHECK( ec.value() == lib4::boo_boo.value() ); + BOOST_CHECK( ec.category() == lib4::lib4_error_category ); + + BOOST_CHECK( ec == boost::system::posix::io_error ); + + boost::system::error_code ec4( lib4::boo_boo.value()+100, + lib4::lib4_error_category ); + BOOST_CHECK( ec4.default_error_condition().category() + == lib4::lib4_error_category ); + + // Test 3 + + //test3::run(); - // asio did not supply decoders, so test the defaults - BOOST_CHECK( ec.to_errno() == EOTHER ); - BOOST_CHECK( ec.message() == "API error" ); - BOOST_CHECK( ec.wmessage() == L"API error" ); return 0; } diff --git a/test/header_only_test.cpp b/test/header_only_test.cpp new file mode 100644 index 0000000..0f4e17b --- /dev/null +++ b/test/header_only_test.cpp @@ -0,0 +1,31 @@ +// error_code_test.cpp -----------------------------------------------------// + +// Copyright Beman Dawes 2007 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/system + +//----------------------------------------------------------------------------// + +// VC++ 8.0 warns on usage of certain Standard Library and API functions that +// can cause buffer overruns or other possible security issues if misused. +// See http://msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC/default.aspx +// But the wording of the warning is misleading and unsettling, there are no +// portable altersystem functions, and VC++ 8.0's own libraries use the +// functions in question. So turn off the warnings. +#define _CRT_SECURE_NO_DEPRECATE +#define _SCL_SECURE_NO_DEPRECATE + +#define BOOST_ERROR_CODE_HEADER_ONLY + +#include + +#include + +int test_main( int, char*[] ) +{ + boost::system::error_code ec( 0, boost::system::system_category ); + return 0; +} diff --git a/test/system_error_test.cpp b/test/system_error_test.cpp index d3dbec6..9158fb9 100644 --- a/test/system_error_test.cpp +++ b/test/system_error_test.cpp @@ -10,7 +10,7 @@ //----------------------------------------------------------------------------// // VC++ 8.0 warns on usage of certain Standard Library and API functions that -// can be cause buffer overruns or other possible security issues if misused. +// can cause buffer overruns or other possible security issues if misused. // See http://msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC/default.aspx // But the wording of the warning is misleading and unsettling, there are no // portable alternative functions, and VC++ 8.0's own libraries use the @@ -23,24 +23,23 @@ #include #ifdef BOOST_WINDOWS_API -# include +#include #endif using boost::system::system_error; using boost::system::error_code; -using boost::system::errno_ecat; -using boost::system::no_message; +using boost::system::system_category; #define TEST(x,v,w) test(#x,x,v,w) namespace { void test( const char * desc, const system_error & ex, - error_code::value_type v, const char * str ) + int v, const char * str ) { std::cout << "test " << desc << "\n what() returns \"" << ex.what() << "\"\n"; BOOST_CHECK( ex.code().value() == v ); - BOOST_CHECK( ex.code().category() == errno_ecat ); + BOOST_CHECK( ex.code().category() == system_category ); # ifdef BOOST_WINDOWS_API BOOST_CHECK( std::string( ex.what() ) == str ); if ( std::string( ex.what() ) != str ) @@ -56,29 +55,22 @@ int test_main( int, char *[] ) { // all combinations of constructors: - system_error se_0( error_code(0, errno_ecat) ); - system_error se_1( 1, errno_ecat ); - system_error se_0_m( error_code(0, errno_ecat), "se_0_m" ); - system_error se_1_m( 1, errno_ecat, "se_1_m" ); - system_error se_0_nm( error_code(0, errno_ecat), "" ); - system_error se_1_nm( 1, errno_ecat, "" ); - system_error se_0_m_im( error_code(0, errno_ecat), "se_0_m_im", no_message ); - system_error se_1_m_im( 1, errno_ecat, "se_1_m_im", no_message ); - system_error se_0_nm_im( error_code(0, errno_ecat), "", no_message ); - system_error se_1_nm_im( 1, errno_ecat, "", no_message ); - system_error se_1u_m( uvalue, errno_ecat, "se_1u_m" ); + system_error se_0_m( error_code(0, system_category), "se_0_m" ); + system_error se_1_m( 1, system_category, "se_1_m" ); + system_error se_0_nm( error_code(0, system_category), "" ); + system_error se_1_nm( 1, system_category, "" ); + system_error se_0_nmx( error_code(0, system_category), "" ); + system_error se_1_nmx( 1, system_category, "" ); + system_error se_1u_m( uvalue, system_category, "se_1u_m" ); - TEST( se_0, 0, "" ); - TEST( se_1, 1, "Operation not permitted" ); TEST( se_0_m, 0, "se_0_m" ); - TEST( se_1_m, 1, "se_1_m: Operation not permitted" ); + TEST( se_1_m, 1, "se_1_m: Incorrect function" ); TEST( se_0_nm, 0, "" ); - TEST( se_1_nm, 1, "Operation not permitted" ); - TEST( se_0_m_im, 0, "se_0_m_im" ); - TEST( se_1_m_im, 1, "se_1_m_im" ); - TEST( se_0_nm_im, 0, "" ); - TEST( se_1_nm_im, 1, "" ); - TEST( se_1u_m, 1, "se_1u_m: Operation not permitted" ); + TEST( se_1_nm, 1, "Incorrect function" ); + TEST( se_0_nmx, 0, "" ); + TEST( se_1_nmx, 1, "Incorrect function" ); + TEST( se_1u_m, 1, "se_1u_m: Incorrect function" ); + return 0; }