summaryrefslogtreecommitdiffstats
blob: 030ab7080ff6c9a65624378a0d655fe9d9db4006 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//  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

//----------------------------------------------------------------------------//

#include <boost/config/warning_disable.hpp>

// define BOOST_SYSTEM_SOURCE so that <boost/system/config.hpp> knows
// the library is being built (possibly exporting rather than importing code)
#define BOOST_SYSTEM_SOURCE 

#include <boost/system/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/cerrno.hpp>
#include <vector>
#include <cstdlib>
#include <cassert>

using namespace boost::system;
using namespace boost::system::posix_error;

#include <cstring> // for strerror/strerror_r

# if defined( BOOST_WINDOWS_API )
#   include <windows.h>
#   ifndef ERROR_INCORRECT_SIZE
#    define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS
#   endif
# endif

//----------------------------------------------------------------------------//

namespace
{
  //  standard error categories  ---------------------------------------------//

  class generic_error_category : public error_category
  {
  public:
    generic_error_category(){}
    const char *   name() const;
    std::string    message( int ev ) const;
  };

  class system_error_category : public error_category
  {
  public:
    system_error_category(){}
    const char *        name() const;
    std::string         message( int ev ) const;
    error_condition     default_error_condition( int ev ) const;
  };

  //  generic_error_category implementation  ---------------------------------//

  const char * generic_error_category::name() const
  {
    return "generic";
  }

  std::string generic_error_category::message( int ev ) const
  {
    static std::string unknown_err( "Unknown error" );
  // 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))\
     || (defined(__QNXNTO__))
      const char * c_str = std::strerror( ev );
      return  c_str
        ? std::string( c_str )
        : unknown_err;
  # else  // use strerror_r
      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  c_str
        ? std::string( c_str )
        : unknown_err;
  #  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 defined (__sgi)
        const char * c_str = strerror( ev );
        result = 0;
      return  c_str
        ? std::string( c_str )
        : unknown_err;
  #  else
        result = strerror_r( ev, bp, sz );
  #  endif
        if (result == 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<char*>(std::malloc( sz ))) == 0 )
            return std::string( "ENOMEM" );
        }
      }
      std::string msg;
      try
      {
        msg = ( ( result == invalid_argument ) ? "Unknown error" : bp );
      }

#   ifndef BOOST_NO_EXCEPTIONS
      // See ticket #2098
      catch(...)
      {
        // just eat the exception
      }
#   endif

      if ( sz > sizeof(buf) ) std::free( bp );
      sz = 0;
      return msg;
  #  endif   // else POSIX version of strerror_r
  # endif  // else use strerror_r
  }
  //  system_error_category implementation  --------------------------------// 

  const char * system_error_category::name() const
  {
    return "system";
  }

  error_condition system_error_category::default_error_condition( int ev ) const
  {
    switch ( ev )
    {
    case 0: return make_error_condition( success );
  # if defined(BOOST_POSIX_API)
    // POSIX-like O/S -> posix_errno decode table  ---------------------------//
    case E2BIG: return make_error_condition( argument_list_too_long );
    case EACCES: return make_error_condition( permission_denied );
    case EADDRINUSE: return make_error_condition( address_in_use );
    case EADDRNOTAVAIL: return make_error_condition( address_not_available );
    case EAFNOSUPPORT: return make_error_condition( address_family_not_supported );
    case EAGAIN: return make_error_condition( resource_unavailable_try_again );
#   if EALREADY != EBUSY  //  EALREADY and EBUSY are the same on QNX Neutrino
    case EALREADY: return make_error_condition( connection_already_in_progress );
#   endif
    case EBADF: return make_error_condition( bad_file_descriptor );
    case EBADMSG: return make_error_condition( bad_message );
    case EBUSY: return make_error_condition( device_or_resource_busy );
    case ECANCELED: return make_error_condition( operation_canceled );
    case ECHILD: return make_error_condition( no_child_process );
    case ECONNABORTED: return make_error_condition( connection_aborted );
    case ECONNREFUSED: return make_error_condition( connection_refused );
    case ECONNRESET: return make_error_condition( connection_reset );
    case EDEADLK: return make_error_condition( resource_deadlock_would_occur );
    case EDESTADDRREQ: return make_error_condition( destination_address_required );
    case EDOM: return make_error_condition( argument_out_of_domain );
    case EEXIST: return make_error_condition( file_exists );
    case EFAULT: return make_error_condition( bad_address );
    case EFBIG: return make_error_condition( file_too_large );
    case EHOSTUNREACH: return make_error_condition( host_unreachable );
    case EIDRM: return make_error_condition( identifier_removed );
    case EILSEQ: return make_error_condition( illegal_byte_sequence );
    case EINPROGRESS: return make_error_condition( operation_in_progress );
    case EINTR: return make_error_condition( interrupted );
    case EINVAL: return make_error_condition( invalid_argument );
    case EIO: return make_error_condition( io_error );
    case EISCONN: return make_error_condition( already_connected );
    case EISDIR: return make_error_condition( is_a_directory );
    case ELOOP: return make_error_condition( too_many_synbolic_link_levels );
    case EMFILE: return make_error_condition( too_many_files_open );
    case EMLINK: return make_error_condition( too_many_links );
    case EMSGSIZE: return make_error_condition( message_size );
    case ENAMETOOLONG: return make_error_condition( filename_too_long );
    case ENETDOWN: return make_error_condition( network_down );
    case ENETRESET: return make_error_condition( network_reset );
    case ENETUNREACH: return make_error_condition( network_unreachable );
    case ENFILE: return make_error_condition( too_many_files_open_in_system );
    case ENOBUFS: return make_error_condition( no_buffer_space );
    case ENODATA: return make_error_condition( no_message_available );
    case ENODEV: return make_error_condition( no_such_device );
    case ENOENT: return make_error_condition( no_such_file_or_directory );
    case ENOEXEC: return make_error_condition( executable_format_error );
    case ENOLCK: return make_error_condition( no_lock_available );
    case ENOLINK: return make_error_condition( no_link );
    case ENOMEM: return make_error_condition( not_enough_memory );
    case ENOMSG: return make_error_condition( no_message );
    case ENOPROTOOPT: return make_error_condition( no_protocol_option );
    case ENOSPC: return make_error_condition( no_space_on_device );
    case ENOSR: return make_error_condition( no_stream_resources );
    case ENOSTR: return make_error_condition( not_a_stream );
    case ENOSYS: return make_error_condition( function_not_supported );
    case ENOTCONN: return make_error_condition( not_connected );
    case ENOTDIR: return make_error_condition( not_a_directory );
  # if ENOTEMPTY != EEXIST // AIX treats ENOTEMPTY and EEXIST as the same value
    case ENOTEMPTY: return make_error_condition( directory_not_empty );
  # endif // ENOTEMPTY != EEXIST
    case ENOTRECOVERABLE: return make_error_condition( state_not_recoverable );
    case ENOTSOCK: return make_error_condition( not_a_socket );
    case ENOTSUP: return make_error_condition( not_supported );
    case ENOTTY: return make_error_condition( inappropriate_io_control_operation );
    case ENXIO: return make_error_condition( no_such_device_or_address );
  # if EOPNOTSUPP != ENOTSUP
    case EOPNOTSUPP: return make_error_condition( operation_not_supported );
  # endif // EOPNOTSUPP != ENOTSUP
    case EOVERFLOW: return make_error_condition( value_too_large );
    case EOWNERDEAD: return make_error_condition( owner_dead );
    case EPERM: return make_error_condition( operation_not_permitted );
    case EPIPE: return make_error_condition( broken_pipe );
    case EPROTO: return make_error_condition( protocol_error );
    case EPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
    case EPROTOTYPE: return make_error_condition( wrong_protocol_type );
    case ERANGE: return make_error_condition( result_out_of_range );
    case EROFS: return make_error_condition( read_only_file_system );
    case ESPIPE: return make_error_condition( invalid_seek );
    case ESRCH: return make_error_condition( no_such_process );
    case ETIME: return make_error_condition( stream_timeout );
    case ETIMEDOUT: return make_error_condition( timed_out );
    case ETXTBSY: return make_error_condition( text_file_busy );
  # if EAGAIN != EWOULDBLOCK
    case EWOULDBLOCK: return make_error_condition( operation_would_block );
  # endif // EAGAIN != EWOULDBLOCK
    case EXDEV: return make_error_condition( cross_device_link );
  #else
    // Windows system -> posix_errno decode table  ---------------------------//
    // see WinError.h comments for descriptions of errors
    case ERROR_ACCESS_DENIED: return make_error_condition( permission_denied );
    case ERROR_ALREADY_EXISTS: return make_error_condition( file_exists );
    case ERROR_BAD_UNIT: return make_error_condition( no_such_device );
    case ERROR_BUFFER_OVERFLOW: return make_error_condition( filename_too_long );
    case ERROR_BUSY: return make_error_condition( device_or_resource_busy );
    case ERROR_BUSY_DRIVE: return make_error_condition( device_or_resource_busy );
    case ERROR_CANNOT_MAKE: return make_error_condition( permission_denied );
    case ERROR_CANTOPEN: return make_error_condition( io_error );
    case ERROR_CANTREAD: return make_error_condition( io_error );
    case ERROR_CANTWRITE: return make_error_condition( io_error );
    case ERROR_CURRENT_DIRECTORY: return make_error_condition( permission_denied );
    case ERROR_DEV_NOT_EXIST: return make_error_condition( no_such_device );
    case ERROR_DEVICE_IN_USE: return make_error_condition( device_or_resource_busy );
    case ERROR_DIR_NOT_EMPTY: return make_error_condition( directory_not_empty );
    case ERROR_DIRECTORY: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid"
    case ERROR_DISK_FULL: return make_error_condition( no_space_on_device );
    case ERROR_FILE_EXISTS: return make_error_condition( file_exists );
    case ERROR_FILE_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
    case ERROR_HANDLE_DISK_FULL: return make_error_condition( no_space_on_device );
    case ERROR_INVALID_ACCESS: return make_error_condition( permission_denied );
    case ERROR_INVALID_DRIVE: return make_error_condition( no_such_device );
    case ERROR_INVALID_FUNCTION: return make_error_condition( function_not_supported );
    case ERROR_INVALID_HANDLE: return make_error_condition( invalid_argument );
    case ERROR_INVALID_NAME: return make_error_condition( invalid_argument );
    case ERROR_LOCK_VIOLATION: return make_error_condition( no_lock_available );
    case ERROR_LOCKED: return make_error_condition( no_lock_available );
    case ERROR_NEGATIVE_SEEK: return make_error_condition( invalid_argument );
    case ERROR_NOACCESS: return make_error_condition( permission_denied );
    case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition( not_enough_memory );
    case ERROR_NOT_READY: return make_error_condition( resource_unavailable_try_again );
    case ERROR_NOT_SAME_DEVICE: return make_error_condition( cross_device_link );
    case ERROR_OPEN_FAILED: return make_error_condition( io_error );
    case ERROR_OPEN_FILES: return make_error_condition( device_or_resource_busy );
    case ERROR_OPERATION_ABORTED: return make_error_condition( operation_canceled );
    case ERROR_OUTOFMEMORY: return make_error_condition( not_enough_memory );
    case ERROR_PATH_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
    case ERROR_READ_FAULT: return make_error_condition( io_error );
    case ERROR_RETRY: return make_error_condition( resource_unavailable_try_again );
    case ERROR_SEEK: return make_error_condition( io_error );
    case ERROR_SHARING_VIOLATION: return make_error_condition( permission_denied );
    case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition( too_many_files_open );
    case ERROR_WRITE_FAULT: return make_error_condition( io_error );
    case ERROR_WRITE_PROTECT: return make_error_condition( permission_denied );
    case WSAEACCES: return make_error_condition( permission_denied );
    case WSAEADDRINUSE: return make_error_condition( address_in_use );
    case WSAEADDRNOTAVAIL: return make_error_condition( address_not_available );
    case WSAEAFNOSUPPORT: return make_error_condition( address_family_not_supported );
    case WSAEALREADY: return make_error_condition( connection_already_in_progress );
    case WSAEBADF: return make_error_condition( bad_file_descriptor );
    case WSAECONNABORTED: return make_error_condition( connection_aborted );
    case WSAECONNREFUSED: return make_error_condition( connection_refused );
    case WSAECONNRESET: return make_error_condition( connection_reset );
    case WSAEDESTADDRREQ: return make_error_condition( destination_address_required );
    case WSAEFAULT: return make_error_condition( bad_address );
    case WSAEHOSTUNREACH: return make_error_condition( host_unreachable );
    case WSAEINPROGRESS: return make_error_condition( operation_in_progress );
    case WSAEINTR: return make_error_condition( interrupted );
    case WSAEINVAL: return make_error_condition( invalid_argument );
    case WSAEISCONN: return make_error_condition( already_connected );
    case WSAEMFILE: return make_error_condition( too_many_files_open );
    case WSAEMSGSIZE: return make_error_condition( message_size );
    case WSAENAMETOOLONG: return make_error_condition( filename_too_long );
    case WSAENETDOWN: return make_error_condition( network_down );
    case WSAENETRESET: return make_error_condition( network_reset );
    case WSAENETUNREACH: return make_error_condition( network_unreachable );
    case WSAENOBUFS: return make_error_condition( no_buffer_space );
    case WSAENOPROTOOPT: return make_error_condition( no_protocol_option );
    case WSAENOTCONN: return make_error_condition( not_connected );
    case WSAENOTSOCK: return make_error_condition( not_a_socket );
    case WSAEOPNOTSUPP: return make_error_condition( operation_not_supported );
    case WSAEPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
    case WSAEPROTOTYPE: return make_error_condition( wrong_protocol_type );
    case WSAETIMEDOUT: return make_error_condition( timed_out );
    case WSAEWOULDBLOCK: return make_error_condition( operation_would_block );
  #endif
    default: return error_condition( ev, system_category );
    }
  }

# if !defined( BOOST_WINDOWS_API )

  std::string system_error_category::message( int ev ) const
  {
    return generic_category.message( ev );
  }
# else
// 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:
//
//<http://boost.cvs.sourceforge.net/boost/boost/boost/asio/system_exception.hpp?revision=1.1&view=markup>
//
//in the implementation of what() for an example.
//
//Cheers,
//Chris
  std::string system_error_category::message( int ev ) const
  {
# ifndef BOOST_NO_ANSI_APIS  
    LPVOID lpMsgBuf;
    DWORD retval = ::FormatMessageA( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        ev,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPSTR) &lpMsgBuf,
        0,
        NULL 
    );
    if (retval == 0)
        return std::string("Unknown error");
        
    std::string str( static_cast<LPCSTR>(lpMsgBuf) );
    ::LocalFree( lpMsgBuf ); // free the buffer
# else  // WinCE workaround
    LPVOID lpMsgBuf;
    DWORD retval = ::FormatMessageW( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        ev,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPWSTR) &lpMsgBuf,
        0,
        NULL 
    );
    if (retval == 0)
        return std::string("Unknown error");
    
    int num_chars = (wcslen( static_cast<LPCWSTR>(lpMsgBuf) ) + 1) * 2;
    LPSTR narrow_buffer = (LPSTR)_alloca( num_chars );
    if (::WideCharToMultiByte(CP_ACP, 0, static_cast<LPCWSTR>(lpMsgBuf), -1, narrow_buffer, num_chars, NULL, NULL) == 0)
        return std::string("Unknown error");

    std::string str( narrow_buffer );
    ::LocalFree( lpMsgBuf ); // free the buffer
# endif
    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;
  }
# endif

} // unnamed namespace

namespace boost
{
  namespace system
  {

    BOOST_SYSTEM_DECL error_code throws; // "throw on error" special error_code;
                                         //  note that it doesn't matter if this
                                         //  isn't initialized before use since
                                         //  the only use is to take its
                                         //  address for comparison purposes

    BOOST_SYSTEM_DECL const error_category & get_system_category()
    {
      static const system_error_category  system_category_const;
      return system_category_const;
    }

    BOOST_SYSTEM_DECL const error_category & get_generic_category()
    {
      static const generic_error_category generic_category_const;
      return generic_category_const;
    }

  } // namespace system
} // namespace boost