<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html;charset=iso-8859-1">
<title>Revised system_error R1</title>
</head>

<body>

<a href="mailto:bkoz@redhat.com">Benjamin Kosnik</a><br>
Document number: N2303=07-0163<br>
2007-06-12<br>
<hr>

<h1 align=center>Revised system_error</h1>

<h2 align=center>Revision 2</h2>

<p>
This paper details possible corrections to the error handling and
diagnostics machinery detailed in <a
href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2241.html">N2241</a>,
which was voted into the working draft for C++0x at the Oxford
meeting. In particular, it advocates replacing all of section 19.4 in
the working draft with the text below.
</p>

<h3><a name="Header">Header</a> &lt;system_error&gt;</h3>
<pre>
namespace std
{
  struct error_catalog;
  struct system_error;
}
</pre>

<h3><a name="error_catalog"></a> class <code>error_catalog</code> </h3>

<p>The class <code>error_catalog</code> is a <code>std::locale</code>
aware map between a positive integer numeric value and a
null-terminated character sequence providing an elaborated description
of the specific error. It is designed for exception-safe use, with the
only possible exception path being the non-default constructor for
named locales. In particular, all member function operations after
construction are exception-free.
</p>

<p>It is assumed that all the system-level error conditions needed to
build C++0x library facilities will be represented in this class as
compile-time data members. This provides a safer nested scope for
compile-time querying, and less compressed identifiers than the
equivalent C or POSIX macros.
</p>

<pre>
namespace std
{
  struct error_catalog
  {
    typedef int value_type;

    static const value_type address_family_not_supported = 	EAFNOSUPPORT;
    static const value_type address_in_use = 			EADDRINUSE;
    static const value_type address_not_available = 	   	EADDRNOTAVAIL;
    static const value_type already_connected = 	   	EISCONN;
    static const value_type argument_list_too_long = 	   	E2BIG;
    static const value_type argument_out_of_domain = 	   	EDOM;
    static const value_type bad_address = 		   	EFAULT;
    static const value_type bad_file_descriptor = 	   	EBADF;
    static const value_type bad_message = 		   	EBADMSG;
    static const value_type broken_pipe = 		   	EPIPE;
    static const value_type connection_aborted = 	   	ECONNABORTED;
    static const value_type connection_refused = 	   	ECONNREFUSED;
    static const value_type connection_reset = 		   	ECONNRESET;
    static const value_type cross_device_link = 	   	EXDEV;
    static const value_type destination_address_required = 	EDESTADDRREQ;
    static const value_type device_or_resource_busy = 	   	EBUSY;
    static const value_type directory_not_empty = 	   	ENOTEMPTY;
    static const value_type executable_format_error = 	   	ENOEXEC;
    static const value_type file_exists = 	       	   	EEXIST;
    static const value_type file_too_large = 		   	EFBIG;
    static const value_type filename_too_long = 	   	ENAMETOOLONG;
    static const value_type function_not_supported = 	   	ENOSYS;
    static const value_type host_unreachable = 		   	EHOSTUNREACH;
    static const value_type identifier_removed = 	   	EIDRM;
    static const value_type illegal_byte_sequence = 	   	EILSEQ;
    static const value_type inappropriate_io_control_operation =ENOTTY;
    static const value_type interrupted = 		   	EINTR;
    static const value_type invalid_argument = 		   	EINVAL;
    static const value_type invalid_seek = 		   	ESPIPE;
    static const value_type io_error = 			   	EIO;
    static const value_type is_a_directory = 		   	EISDIR;
    static const value_type message_too_long = 		   	EMSGSIZE; 
    static const value_type network_down = 		   	ENETDOWN;
    static const value_type network_reset = 		   	ENETRESET;
    static const value_type network_unreachable = 	   	ENETUNREACH;
    static const value_type no_buffer_space = 		   	ENOBUFS;
    static const value_type no_child_process = 		   	ECHILD;
    static const value_type no_link = 			   	ENOLINK;
    static const value_type no_lock_available = 	   	ENOLCK;
    static const value_type no_message_available = 	   	ENODATA;
    static const value_type no_message = 		   	ENOMSG;
    static const value_type no_space_on_device = 	   	ENOSPC;
    static const value_type no_stream_resources = 	   	ENOSR;
    static const value_type no_such_device_or_address =    	ENXIO;
    static const value_type no_such_device = 		   	ENODEV;
    static const value_type no_such_file_or_directory =    	ENOENT;
    static const value_type no_such_process = 		   	ESRCH;
    static const value_type not_a_directory = 		   	ENOTDIR;
    static const value_type not_a_socket = 		   	ENOTSOCK;
    static const value_type not_a_stream = 		   	ENOSTR;
    static const value_type not_connected = 		   	ENOTCONN;
    static const value_type not_enough_memory = 	   	ENOMEM;
    static const value_type not_supported = 		   	ENOTSUP;
    static const value_type operation_already_in_progress =  	EALREADY; 
    static const value_type operation_canceled = 	   	ECANCELED;
    static const value_type operation_in_progress = 	   	EINPROGRESS;
    static const value_type operation_not_permitted = 	   	EPERM;
    static const value_type operation_not_supported = 	   	EOPNOTSUPP;
    static const value_type owner_dead = 		   	EOWNERDEAD;
    static const value_type permission_denied = 	   	EACCES;
    static const value_type protocol_error = 		   	EPROTO;
    static const value_type protocol_not_available = 	   	ENOPROTOOPT; 
    static const value_type protocol_not_supported = 	   	EPROTONOSUPPORT;
    static const value_type read_only_file_system = 	   	EROFS;
    static const value_type resource_deadlock_would_occur = 	EDEADLK;
    static const value_type result_out_of_range = 	   	ERANGE;
    static const value_type state_not_recoverable = 	   	ENOTRECOVERABLE;
    static const value_type stream_timeout = 		   	ETIME;
    static const value_type text_file_busy = 		   	ETXTBSY;
    static const value_type timed_out = 		   	ETIMEDOUT;
    static const value_type too_many_files_open_in_system = 	ENFILE;
    static const value_type too_many_files_open = 	   	EMFILE;
    static const value_type too_many_links = 		   	EMLINK;
    static const value_type too_many_synbolic_link_levels = 	ELOOP;
    static const value_type try_again = 			EAGAIN; 
    static const value_type value_too_large = 		   	EOVERFLOW;
    static const value_type wrong_protocol_type; = 	   	EPROTOTYPE;

    virtual const value_type
    last_value() const throw();

    virtual bool
    is_valid_value(value_type) const throw();

    virtual const char*
    str(value_type) const throw();

    const locale&
    getloc() const throw();

    error_catalog(const locale& __loc = locale::classic()) throw();

    error_catalog(const char* __name);

    virtual ~error_catalog() throw();

    bool 
    operator==(const error_catalog&) const throw();

    bool 
    operator!=(const error_catalog&) const throw();

  private:
    const locale	_M_loc;
  };
}
</pre>

<p> Defined values for the const static data members of this class are
all non-zero, positive integer values.
</p>

<p> Changes from N2241 are: change
<code>resource_unavailable_try_again</code> to <code>try_again</code>,
<code>no_protocol_option</code> to
<code>protocol_not_available</code>,
<code>connection_already_in_progress</code> to
<code>operation_already_in_progress</code>, <code>message_size</code>
to <code>message_too_long</code>. In addition, remove
<code>operation_would_block</code> and <code>other</code>.
</p>


<p> Definitions for the member functions of this class are as
follows. Please note, the requirements for virtual member functions
are the same for the base class and any derived classes.
</p>

<pre> virtual const value_type last_value() const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> A <code>const value_type</code> representing the largest
  value <code>n</code> such that <code>is_valid_value(n)</code> is
  <code>true</code>.</p>
</blockquote>

<pre> virtual bool is_valid_value(value_type __n) const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> If the argument <code>__n</code> is equal to any
  of the static constant data members of <code>error_catalog</code>,
  then <code>true</code>, else <code>false</code>.</p>
</blockquote>

<pre> virtual const char* str(value_type __n) const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> If <code>is_valid_value(__n)</code>, returns a
  null-terminated character sequence corresponding to <code>__n</code>
  in the <code>std::locale</code> that would be returned by
  <code>getloc</code>, else an empty string (ie, <code>""</code>).</p>
  <p><i>Note:</i> An example of the expected behavior is as follows.</p>
  <blockquote>
  <pre>
  std::locale loc;
  std::string s;
  try
    { loc = std::locale("fr_FR"); }
  catch(...)
    { // Construction of named locale didn't work. }

  std::error_catalog e1(loc);
  s = e1.str(std::error_catalog::file_exists);
  bool b1 = s == "Le fichier existe.";

  std::error_catalog e2;
  s = e2.str(std::error_catalog::file_exists);
  bool b2 = s == "File exists";
  </pre>
  </blockquote>
</blockquote>

<pre> const locale& getloc() const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> A <code>const std::locale</code> reference to
  the current locale of the <code>error_catalog</code> instance.</p>
</blockquote>

<pre> error_catalog(const char* __name);
</pre>
<blockquote>
  <p><i>Effects:</i> Construct an <code>error_catalog</code> object localized 
  for the <code>std::locale</code> named by the <code>const char*</code> argument.</p>
  <p><i>Postcondition:</i> <code>getloc() == std::locale(__name)</code>.</p>
  <p><i>Throws:</i> If <code>__name</code> is not a valid name,
  construction of <code>std::locale</code> could fail, which may throw
  <code>std::runtime_error</code>.</p>
 <p><i>Note:</i> Valid names could be <code>"POSIX"</code> or
 <code>"C"</code>, or any other implementation-defined-as-valid
 string. </p>
</blockquote>

<pre> error_catalog(const locale& __loc) throw();
</pre>
<blockquote>
  <p><i>Effects:</i> Construct an <code>error_catalog</code> object
  localized for the <code>std::locale</code> named by the
  <code>__loc</code> argument. The default argument is
  <code>std::locale::classic()</code></p>
  <p><i>Postcondition:</i> <code>getloc() == __loc</code>.</p>
</blockquote>

<pre> bool operator==(const error_catalog& __other) const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> If <code>getloc() == __other.getloc()</code> and
  <code>typeinfo(*this) == typeinfo(__other)</code>, then return
  <code>true</code>. Else return <code>false</code>.</p>
</blockquote>

<pre> bool operator!=(const error_catalog& __other) const throw();
</pre>
<blockquote>
  <p><i>Returns:</i> <code>!(*this == __other)</code></p>
</blockquote>


<h3><a name="system_error"></a> class <code>system_error</code> </h3>

<p>The class <code>system_error</code> is an exception derived from
<code>std::runtime_error</code> that is designed to be useful for
reporting the detailed character sequences corresponding to a given
<code>error_catalog</code> and <code>error_catalog::value_type</code>.
</p>

<pre>
namespace std
{
  class system_error : public std::runtime_error
  {
  public:

    system_error(const string&);

    system_error(error_catalog::value_type, const error_catalog&);
  };
}
</pre>

<p> Definitions for the member functions of this class are as follows.
</p>

<pre> system_error(const string& __s);
</pre>
<blockquote>
  <p><i>Postcondition:</i> <code>strcmp(what(), __s.c_str()) == 0</code>.</p>
</blockquote>

<pre> error_catalog(error_catalog::value_type __v, const error_catalog& __cat);
</pre>
<blockquote>
  <p><i>Postcondition:</i> <code>strcmp(what(), __cat.str(__v)) == 0</code>.</p>
</blockquote>


<h3><a name="extending"></a> Extending by derivation for domain-specific errors </h3>

<p> The standard components detailed above are designed so that
consumers of <code>system_error</code> will be able to extend
<code>namespace std</code> components for non-standard domains.
</p>

<p> As a example of extensibility, here's a demonstration of an
non-localized set of new error conditions, perhaps for a inkjet
printer, implemented as a derived class of
<code>error_catalog</code>. As can be seen, it's quite
straightforward.
</p>

<blockquote>
<pre>
namespace __gnu_test
{
  struct derived_error_catalog : virtual public std::error_catalog
  {
    typedef std::error_catalog base_type;

    static const value_type out_of_ink = 20001;
    static const value_type out_of_paper = 20002;
  
    virtual bool
    is_valid_value(value_type __v) const throw()
    {
      bool ret = false;
      if (base_type::is_valid_value(__v))
	ret = true;
      else
	{
	  if (__v == out_of_ink || __v == out_of_paper)
	    ret = true;
	}
      return ret;
    }
  
    virtual const char*
    str(value_type __v) const throw()
    {
      const char* s = NULL;
      const char* s1 = "Out of Ink";
      const char* s2 = "Out of Paper";
      if (is_valid_value(__v))
	{
	  if (base_type::is_valid_value(__v))
	    s = base_type::str(__v);
	  else
	    {
	      switch (__v)
		{
		case out_of_ink:
		  s = s1;
		  break;
		case out_of_paper:
		  s = s2;
		  break;
		default:
		  s;
		}
	    }
	}
      return s;
    }

    virtual const value_type
    last_value() const throw() { return out_of_paper; }
  };
}
</pre>
</blockquote>

<p> The code below is but one example: it would be possible for
operating system vendors to derive os-specific error catalogs. (For
instance, a possible Microsoft extension could conceivably be
<code>win_error_catalog</code>, with the requisite sixteen thousand
constants mapped to locale-specific error strings.)
</p>

<p> Another possibility for extensions to <code>error_catalog</code>
would be a derived class for user-specified wide-character messages.
In this way it would be possible for users to specify unicode (or
other encoding) messages for either the standard error conditions or
some extended catalog of error conditions, without bogging down the
required system behavior.
</p>

<h3><a name="acknowledgements"></a> Acknowledgments </h3>
<p>Ulrich Drepper commented on draft versions of this paper, sanity
checked <code>C</code> and <code>POSIX</code> usage, suggested better
semantics for testing equality, and championed the strongest possible
exception specifications.
</p>

<h3><a name="references"></a> References </h3>

<p>
<a href="http://msdn2.microsoft.com/en-us/library/ms681381.aspx"> Microsoft System Error Codes </a>
</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2241.html">Diagnostics Enhancements for C++0x (Rev. 1) </a>
</p>

<p> Becker, Pete, Working Draft, Standard for Programming Language C++, N2284=07-0144
</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2302.html">Issues in system_error </a>
</p>


</body>

</html>