commit f3c8c7465655ee83a44fdc3c9b8de635a32c8c9d Author: Beman Dawes Date: Fri Nov 3 16:57:30 2006 +0000 Bring into compliance with N2066, TR2 Diagnostics Enhancements. Tests passing on Win32, Linux, on most modern compilers. [SVN r35823] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/build/Jamfile b/build/Jamfile new file mode 100644 index 0000000..8a45fa9 --- /dev/null +++ b/build/Jamfile @@ -0,0 +1,56 @@ +# 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 copy at http://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 new file mode 100644 index 0000000..3674e50 --- /dev/null +++ b/doc/error_code.html @@ -0,0 +1,265 @@ + + + + + + + +Boost class error_code documentation + + + + + +

Header boost/system/error_code.hpp

+

Introduction
+Synopsis
+Class error_category
+    Members
+Class error_code
+    Members
+Non-member functions
+Acknowledgments

+

Introduction

+

This header provides components used to report errors from the operating +system or other low-level application program interface (API). It is based on the Diagnostics portion of the TR2 filesystem +proposal.

+

Class error_code encapsulates an error +code, usually one returned by an API. Class +error_category encapsulates +an identifier for a +particular kind of error code. Users or +third-parties may add additional error categories.

+

Synopsis

+
namespace boost
+{
+  namespace system
+  {
+    class error_code;
+
+    typedef int         (*errno_decoder)( const error_code & );
+    typedef std::string (*message_decoder)( const error_code & );
+    typedef wstring_t   (*wmessage_decoder)( const error_code & );
+
+    class error_category : public identifier< uint_least32_t, error_category >
+    {
+    public:
+      error_category();
+      explicit error_category( value_type v );
+    };
+
+    const error_category  errno_ecat = unspecified-value;
+    const error_category  native_ecat = unspecified-value;
+
+    class error_code
+    {
+    public:
+      typedef boost::int_least32_t  value_type;
+
+      // constructors:
+      error_code();
+      error_code( value_type val, error_category cat );
+      void assign(value_type val, error_category cat);
+
+      // observers:
+      value_type      value() const;
+      error_category  category() const;
+      int             to_errno() const;  // name chosen to limit surprises
+                                         // see Kohlhoff June 28 '06 boost posting
+      std::string     message() const;
+      std::wstring    wmessage() const;
+
+      // relationals:
+      bool operator==( const error_code & rhs ) const;
+      bool operator!=( const error_code & rhs ) const;
+      bool operator< ( const error_code & rhs ) const;
+      bool operator<=( const error_code & rhs ) const;
+      bool operator> ( const error_code & rhs ) const;
+      bool operator>=( const error_code & rhs ) const;
+
+      operator unspecified-bool-type() const;
+      bool operator!() const;
+
+      // 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 );
+
+    };
+
+    std::size_t hash_value( const error_code & ec );
+    
+  } // namespace system
+} // namespace boost
+

Class error_category

+

Class error_category +encapsulates an identifier for a +particular kind of error code. Users or +third-parties may add additional error categories.

+

For inherited members, see +identifier documentation.

+

Class error_category +members

+
error_category();
+
+

Effects: Constructs an object of class error_category.

+

Postcondition: value() == value_type().

+
+
explicit error_category( value_type v );
+
+

Effects: Constructs an object of class error_category.

+

Postcondition: value() == v.

+
+

Class error_code

+

The value contained by an error_code object is the underlying +API error code itself if the API error code type can be stored in +value_type without loss of any actual values and if 0 represents no +error. Otherwise, the value is an integer that maps to the API error code, with +the exact method of mapping unspecified.

+

Class error_code members

+
error_code();
+
+

Effects: Constructs an object of class error_code.

+

Postcondition: value() == 0 && category() == errno_ecat.

+
+
error_code( value_type val, error_category cat );
+
+

Effects: Constructs an object of class error_code.

+

Postcondition: value() == val && category() == cat.

+
+
void assign(value_type val, error_category cat);
+
+

Postconditions: value() == val && category() == cat.

+
+
value_type value() const;
+
+

Returns: value() as specified by postconditions of the most +recent assign, if any, or of the constructor.

+
+
error_category category() const;
+
+

Returns: category() as specified by postconditions of the most +recent assign, if any, or of the constructor.

+
+
int to_errno() const;
+
+

Effects:  errno_decoder ed;
+       message_decoder md;
+       wmessage_decoder wmd;
+       bool ok( get_decoders( category(), ed, md, +wmd ) );

+

Returns:  If ok && ed, ed(*this), +otherwise EOTHER.

+

[Note: The intent is to return the +ISO/IEC 9945:2003, Portable Operating System Interface (POSIX) error +number that the implementation determines most closely corresponds to +value(). --end note.]

+
+
std::string message() const;
+
+

Effects:  errno_decoder ed;
+       message_decoder md;
+       wmessage_decoder wmd;
+       bool ok( get_decoders( category(), ed, md, +wmd ) );

+

Returns:  If ok && md, md(*this), +otherwise std::string().

+

Remarks: If category() == errno_ec, the string is as +returned by strerror(). Otherwise, the method used by the +implementation to determine the string is unspecified.

+

[Note: The intent is to return a locale sensitive string that describes the error +corresponding to value()--end note.]

+
+
wstring_t wmessage() const;
+
+

Effects:  errno_decoder ed;
+       message_decoder md;
+       wmessage_decoder wmd;
+       bool ok( get_decoders( category(), ed, md, +wmd ) );

+

Returns:  If ok && wmd, wmd(*this), +otherwise std::wstring().

+

Remarks: If category() == errno_ec, the string is as +returned by strerror(). Otherwise, the method used by the +implementation to determine the string is unspecified.

+

[Note: The intent is to return a locale sensitive string that describes the error +corresponding to value()--end note.]

+
+
bool operator==(const error_code & rhs) const;
+
+

Returns: value() == rhs.value() && category() == rhs.category().

+
+
bool operator!=(const error_code & rhs) const;
+
+

Returns: !(*this == rhs).

+
+
bool operator<(const error_code & rhs) const;
+
+

Returns: category() < rhs.category() || ( category() == + rhs.category() && value() < rhs.value() ).

+
+
bool operator<=(const error_code & rhs) const;
+
+

Returns: *this == rhs || *this < rhs.

+
+
bool operator>(const error_code & rhs) const;
+
+

Returns: !(*this <= rhs).

+
+
bool operator>=(const error_code & rhs) const;
+
+

Returns: !(*this < rhs).

+
+
operator unspecified-bool-type() const;
+
+

Returns:  value() != value_type() ? unspecified-bool-type + : 0.

+

Throws: nothing.

+

[ Note: This conversion can be used in contexts where a bool +is expected (e.g., an if condition); however, implicit conversions +(e.g., to int) that can occur with bool are not +allowed, eliminating some sources of user error. One possible implementation +choice for this type is pointer-to-member. —end note ]

+
+
bool operator!() const;
+
+

Returns:  value() == value_type().

+
+
static error_category new_category( errno_decoder ed = 0, message_decoder md = 0, wmessage_decoder wmd = 0 );
+
+

Effects: Constructs a new error_category object. + Creates an association between the object and ed,  + md, and wmd.

+

Returns: The object.

+
+
static bool get_decoders( error_category cat, errno_decoder & ed, message_decoder & md, wmessage_decoder & wmd );
+
+

Effects: If cat was created by new_category(), + sets edmd, and wmd + to the respective values associated with cat by + new_category(). Otherwise, no effects.

+

Returns: If cat was created by new_category(), + true, otherwise false.

+
+

Non-member functions

+
std::size_t hash_value( const error_code & ec );
+
+

Returns:  A hash value representing ec.

+
+

Acknowledgements

+

Christopher Kohlhoff and Peter Dimov made important contributions to the + design. Comments and suggestions were also received from Pavel Vozenilek, + Gennaro Prota, Dave Abrahams, Jeff Garland, Iain Hanson, Oliver Kowalke, and + Oleg Abrosimov.

+
+

Last revised: +06 September, 2006

+

© Copyright Beman Dawes, 2006

+

Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at +www.boost.org/ LICENSE_1_0.txt)

+ + + + \ No newline at end of file diff --git a/doc/system_error.html b/doc/system_error.html new file mode 100644 index 0000000..068cbb0 --- /dev/null +++ b/doc/system_error.html @@ -0,0 +1,127 @@ + + + + + + + +Boost system/system_error.hpp documentation + + + + + +

Header boost/system/system_error.hpp

+

Introduction
+Synopsis
+Class system_error
+    Members
+Acknowledgements

+

Introduction

+

This header provides components used to report errors originating from the +operating system or other low-level application program interfaces (API's). It is based on the Diagnostics +portion of the TR2 filesystem proposal.

+

Synopsis

+
namespace boost
+{
+  namespace system
+  {
+    enum message_action { append_message, no_message };
+
+    class system_error : public std::runtime_error
+    {
+    public:
+      explicit system_error( error_code ec );
+
+      system_error( error_code ec, const std::string & what_arg,
+        message_action ma = append_message );
+
+      system_error( error_code::value_type ev, error_category ecat );
+
+      system_error( error_code::value_type ev, error_category ecat,
+        const std::string & what_arg, message_action ma = append_message );
+
+      virtual ~system_error() throw() {}
+
+      const error_code & code() const throw();
+
+      const char * what() const throw();
+
+    private:
+      error_code           m_error_code;      // for exposition only
+      bool                 m_append_message;  // for exposition only
+      mutable std::string  m_what;            // for exposition only
+    };
+  } // namespace system
+} // namespace boost
+

Class system_error

+

Class system_error defines +the type of an object that may be thrown as +an exception to report errors originating from the operating system or other +low-level API's, or used as a base class for more refined exception classes. It +encapsulates an error_code object.

+
+

[Note: A single low-level class, rather than a higher level exception +class hierarchy, is provided to allow users access to low-level error codes +originating from the operating system or other low-level API's, and to +accommodate the open-ended set of errors that may be reported by such API's. +--end note.]

+
+

Class system_error Members

+

explicit system_error( error_code ec );

+
+

Effects: Constructs an object of class system_error.

+

Postcondition: code() == ec && *runtime_error::what() == '\0' + && m_append_message.

+
+
system_error( error_code ec, const std::string & what_arg, message_action ma = append_message );
+
+

Effects: Constructs an object of class system_error.

+

Postcondition: code() == ec && std::string(runtime_error::what()) + == what_arg && m_append_message == ma.

+
+
system_error( error_code::value_type ev, error_category ecat );
+
+

Effects: Constructs an object of class system_error.

+

Postcondition: code() == error_code(ev,ecat) && *runtime_error::what() + == '\0' && m_append_message.

+
+
system_error( error_code::value_type ev, error_category ecat,
+              const std::string & what_arg, message_action ma = append_message );
+
+

Effects: Constructs an object of class system_error.

+

Postcondition: code() == error_code(ev,ecat) && std::string(runtime_error::what()) + == what_arg && m_append_message == ma.

+
+
const error_code & code() const throw();
+
+

Returns:  m_error_code

+
+
const char * what() const throw();
+
+

Returns: If !m_error_code || !m_append_message, + runtime_error::what(). Otherwise, a string as if computed by:

+
+
m_what = runtime_error::what();
+if ( !m_what.empty() ) m_what += ": ";
+m_what += m_error_code.message();
+return m_what.c_str();
+
+
+

Acknowledgements

+

Christopher Kohlhoff and Peter Dimov made important contributions to the + design. Comments and suggestions were also received from Pavel Vozenilek, + Gennaro Prota, Dave Abrahams, Jeff Garland, Iain Hanson, Jeremy Day, Bo + Persson, Oliver Kowalke, and + Oleg Abrosimov.

+
+

Last revised: +22 July, 2006

+

© Copyright Beman Dawes, 2006

+

Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at +www.boost.org/ LICENSE_1_0.txt)

+ + + + \ No newline at end of file diff --git a/include/boost/system/config.hpp b/include/boost/system/config.hpp new file mode 100644 index 0000000..6709eb4 --- /dev/null +++ b/include/boost/system/config.hpp @@ -0,0 +1,75 @@ +// boost/system/config.hpp -------------------------------------------------// + +// Copyright Beman Dawes 2003, 2006 + +// 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 http://www.boost.org/libs/system for documentation. + +#ifndef BOOST_SYSTEM_CONFIG_HPP +#define BOOST_SYSTEM_CONFIG_HPP + +#include + +// BOOST_POSIX_API or BOOST_WINDOWS_API specify which API to use. +// If not specified, a sensible default will be applied. + +# if defined( BOOST_WINDOWS_API ) && defined( BOOST_POSIX_API ) +# error both BOOST_WINDOWS_API and BOOST_POSIX_API are defined +# elif !defined( BOOST_WINDOWS_API ) && !defined( BOOST_POSIX_API ) +# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) +# define BOOST_WINDOWS_API +# else +# define BOOST_POSIX_API +# endif +# endif + +// 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 +//# endif + +#ifdef BOOST_HAS_DECLSPEC // defined in config system +// we need to import/export our code only if the user has specifically +// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost +// libraries to be dynamically linked, or BOOST_SYSTEM_DYN_LINK +// if they want just this one to be dynamically liked: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK) +// export if this is our own source, otherwise import: +#ifdef BOOST_SYSTEM_SOURCE +# define BOOST_SYSTEM_DECL __declspec(dllexport) +#else +# define BOOST_SYSTEM_DECL __declspec(dllimport) +#endif // BOOST_SYSTEM_SOURCE +#endif // DYN_LINK +#endif // BOOST_HAS_DECLSPEC +// +// if BOOST_SYSTEM_DECL isn't defined yet define it now: +#ifndef BOOST_SYSTEM_DECL +#define BOOST_SYSTEM_DECL +#endif + +// enable automatic library variant selection ------------------------------// + +#if !defined(BOOST_SYSTEM_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_SYSTEM_NO_LIB) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_system +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SYSTEM_DYN_LINK) +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#endif // BOOST_SYSTEM_CONFIG_HPP + diff --git a/include/boost/system/error_code.hpp b/include/boost/system/error_code.hpp new file mode 100644 index 0000000..262639f --- /dev/null +++ b/include/boost/system/error_code.hpp @@ -0,0 +1,147 @@ +// boost/system/error_code.hpp ---------------------------------------------// + +// Copyright Beman Dawes 2006 + +// 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 + +#ifndef BOOST_SYSTEM_ERROR_CODE_HPP +#define BOOST_SYSTEM_ERROR_CODE_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include // must be the last #include + +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; + + // typedefs for registering additional decoders -------------------------// + + typedef int (*errno_decoder)( const error_code & ); + typedef std::string (*message_decoder)( const error_code & ); + typedef wstring_t (*wmessage_decoder)( const error_code & ); + + // class error_category ------------------------------------------------// + + class BOOST_SYSTEM_DECL error_category : public identifier< uint_least32_t, error_category > + { + public: + error_category() + : boost::identifier< uint_least32_t, error_category >(0){} + explicit error_category( value_type v ) + : boost::identifier< uint_least32_t, error_category >(v){} + }; + + // predefined error categories -----------------------------------------// + + const error_category errno_ecat(0); // unspecified value + +# ifdef BOOST_WINDOWS_API + const error_category native_ecat(1); // unspecified value +# else + const error_category native_ecat(0); // unspecified value +# endif + + // class error_code ----------------------------------------------------// + + class BOOST_SYSTEM_DECL error_code + { + 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) {} + + + // 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); } + + 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; + } + + bool operator!() const // true if no error + { + return m_value == value_type(); + } + + // 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 ); + + private: + value_type m_value; + error_category m_category; + }; + + // non-member functions ------------------------------------------------// + + inline std::size_t hash_value( const error_code & ec ) + { + return static_cast(ec.value()) + + (static_cast(ec.category().value()) << 16 ); + } + + } // namespace system +} // namespace boost + +#include // pops abi_prefix.hpp pragmas + +#endif // BOOST_SYSTEM_ERROR_CODE_HPP + + diff --git a/include/boost/system/system_error.hpp b/include/boost/system/system_error.hpp new file mode 100644 index 0000000..cb94dcf --- /dev/null +++ b/include/boost/system/system_error.hpp @@ -0,0 +1,78 @@ +// Boost system_error.hpp --------------------------------------------------// + +// Copyright Beman Dawes 2006 + +// 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) + +#ifndef BOOST_SYSTEM_ERROR_HPP +#define BOOST_SYSTEM_ERROR_HPP + +#include +#include +#include +#include + +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) {} + + 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(); + } + + + private: + error_code m_error_code; + mutable std::string m_what; + bool m_append_message; + }; + + } // namespace system +} // namespace boost + +#endif // BOOST_SYSTEM_ERROR_HPP + + diff --git a/src/error_code.cpp b/src/error_code.cpp new file mode 100644 index 0000000..74ffd55 --- /dev/null +++ b/src/error_code.cpp @@ -0,0 +1,310 @@ +// error_code support implementation file ----------------------------------// + +// Copyright Beman Dawes 2002, 2006 + +// 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 be 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 +// functions in question. So turn off the warnings. +#define _CRT_SECURE_NO_DEPRECATE +#define _SCL_SECURE_NO_DEPRECATE + +// define BOOST_SYSTEM_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_SYSTEM_SOURCE + +#include +#include +#include +#include + +using namespace boost::system; + +#include // for strerror/strerror_r + +# ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::strerror; } +# endif + +# if defined( BOOST_WINDOWS_API ) +# include "windows.h" +# ifndef ERROR_INCORRECT_SIZE +# define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS +# endif +# endif + +//----------------------------------------------------------------------------// + +namespace +{ + +#ifdef BOOST_WINDOWS_API + struct native_to_errno_t + { + boost::int32_t native_value; + int to_errno; + }; + + const native_to_errno_t native_to_errno[] = + { + // 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 }, + + // 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 } + }; + + int windows_ed( const error_code & ec ) + { + 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; + } + +// TODO: + +//Some quick notes on the implementation (sorry for the noise if +//someone has already mentioned them): +// +//- The ::LocalFree() usage isn't exception safe. +// +//See: +// +// +// +//in the implementation of what() for an example. +// +//Cheers, +//Chris + + std::string windows_md( const error_code & ec ) + { + LPVOID lpMsgBuf; + ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ec.value(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + std::string str( static_cast(lpMsgBuf) ); + ::LocalFree( lpMsgBuf ); // free the buffer + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + 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 ) + { +# if defined(BOOST_WINDOWS_API) || defined(__hpux) || (defined(__linux) && !defined(__USE_XOPEN2K)) + 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 (;;) + { + if ( (result = strerror_r( ec.value(), bp, sz )) != 0 ) + { +# if defined(__linux) + 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" ); + } + std::string msg( ( result == EINVAL ) ? "EINVAL" : bp ); + if ( sz > sizeof(buf) ) std::free( bp ); + return msg; +# 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) {} + }; + + 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 + + typedef std::vector< decoder_element > decoder_vec_type; + + decoder_vec_type & decoder_vec() + { + static decoder_vec_type dv( init_decoders, + init_decoders + sizeof(init_decoders)/sizeof(decoder_element)); + return dv; + } +} // unnamed namespace + +namespace boost +{ + namespace system + { + BOOST_SYSTEM_DECL error_code throw_on_error; // dummy meaningless value + + 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; + } + + 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; + } + + 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" ); + } + + 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" ); + } + + } // namespace system +} // namespace boost diff --git a/test/error_code_test.cpp b/test/error_code_test.cpp new file mode 100644 index 0000000..f7e73e6 --- /dev/null +++ b/test/error_code_test.cpp @@ -0,0 +1,115 @@ +// error_code_test.cpp -----------------------------------------------------// + +// Copyright Beman Dawes 2006 + +// 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 be 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 +// functions in question. So turn off the warnings. +#define _CRT_SECURE_NO_DEPRECATE +#define _SCL_SECURE_NO_DEPRECATE + +#include +#include + +// Although using directives are not the best programming practice, testing +// with a boost::system using directive increases use scenario coverage. +using namespace boost::system; + +# if defined( BOOST_WINDOWS_API ) +# include "winerror.h" +# include +# endif + +// test_main ---------------------------------------------------------------// + +// TODO: supply a build jam file +// TODO: supply a test jam file +// TODO: same for bjam v2 +// TODO: add message decoder 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 ); + + BOOST_CHECK( !ec ); + BOOST_CHECK( ec.value() == 0 ); + BOOST_CHECK( ec.to_errno() == 0 ); + + BOOST_CHECK( !ec_0_native ); + BOOST_CHECK( ec_0_native.value() == 0 ); + BOOST_CHECK( ec_0_native.to_errno() == 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_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 ); + + 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 ); + +#ifdef BOOST_WINDOWS_API + BOOST_CHECK( ec != ec_0_native ); + + // these tests probe the Windows to_errno decoder + // test the first entry in the decoder table: + ec = error_code( ERROR_FILE_NOT_FOUND, native_ecat ); + BOOST_CHECK( ec.value() == ERROR_FILE_NOT_FOUND ); + BOOST_CHECK( ec.to_errno() == ENOENT ); + + // test the second entry in the decoder table: + ec = error_code( ERROR_PATH_NOT_FOUND, native_ecat ); + BOOST_CHECK( ec.value() == ERROR_PATH_NOT_FOUND ); + BOOST_CHECK( ec.to_errno() == ENOENT ); + + // test the third entry in the decoder table: + ec = error_code( ERROR_ACCESS_DENIED, native_ecat ); + BOOST_CHECK( ec.value() == ERROR_ACCESS_DENIED ); + BOOST_CHECK( ec.to_errno() == EACCES ); + + // test the last regular entry in the decoder table: + ec = error_code( ERROR_WRITE_PROTECT, native_ecat ); + BOOST_CHECK( ec.value() == ERROR_WRITE_PROTECT ); + BOOST_CHECK( ec.to_errno() == EROFS ); + + // test not-in-table condition: + ec = error_code( 1234567890, native_ecat ); + BOOST_CHECK( ec.value() == 1234567890 ); + BOOST_CHECK( ec.to_errno() == EOTHER ); + +#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 new file mode 100644 index 0000000..a61caf2 --- /dev/null +++ b/test/error_code_user_test.cpp @@ -0,0 +1,92 @@ +// error_code_user_test.cpp ------------------------------------------------// + +// Copyright Beman Dawes 2006 + +// 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 + +// ------------------------------------------------------------------------ // +// 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. + +#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 + +int test_main( int, char *[] ) +{ + boost::system::error_code ec; + boost::asio::boo_boo( ec ); + + 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 ); + + // 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 ); + + // 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/system_error_test.cpp b/test/system_error_test.cpp new file mode 100644 index 0000000..41f4612 --- /dev/null +++ b/test/system_error_test.cpp @@ -0,0 +1,84 @@ +// system_error_test.cpp ---------------------------------------------------// + +// Copyright Beman Dawes 2006 + +// 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 be 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 +// functions in question. So turn off the warnings. +#define _CRT_SECURE_NO_DEPRECATE +#define _SCL_SECURE_NO_DEPRECATE + +#include +#include +#include + +#include + +using boost::system::system_error; +using boost::system::error_code; +using boost::system::errno_ecat; +using boost::system::no_message; + +#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 ) + { + std::cout << "test " << desc << "\n what() returns \"" << ex.what() << "\"\n"; + BOOST_CHECK( ex.code().value() == v ); + BOOST_CHECK( ex.code().category() == errno_ecat ); +# ifdef BOOST_WINDOWS_API + BOOST_CHECK( std::string( ex.what() ) == str ); + if ( std::string( ex.what() ) != str ) + std::cout << "expected \"" << str << "\", but what() returned \"" + << ex.what() << "\"\n"; +# endif + } + + const boost::uint_least32_t uvalue = 1u; +} + +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" ); + + 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_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" ); + + return 0; +} + +