Merge /u/frougon/flightgear-simgear/ branch thread-safe-alternative-to-strerror into next

https://sourceforge.net/p/flightgear/simgear/merge-requests/9/
This commit is contained in:
Torsten Dreyer
2016-05-09 10:51:13 +00:00
3 changed files with 78 additions and 0 deletions

View File

@@ -24,11 +24,14 @@
#include <cstring>
#include <sstream>
#include <algorithm>
#include <string.h> // strerror_r() and strerror_s()
#include <errno.h>
#include "strutils.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/package/md5.h>
#include <simgear/compiler.h> // SG_WINDOWS
using std::string;
using std::vector;
@@ -597,6 +600,49 @@ string sanitizePrintfFormat(const string& input)
return input;
}
std::string error_string(int errnum)
{
char buf[512]; // somewhat arbitrary...
// This could be simplified with C11 (annex K, optional...), which offers:
//
// errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum );
// size_t strerrorlen_s( errno_t errnum );
#if defined(SG_WINDOWS)
errno_t retcode;
// Always makes the string in 'buf' null-terminated
retcode = strerror_s(buf, sizeof(buf), errnum);
#elif defined(_GNU_SOURCE)
return std::string(strerror_r(errnum, buf, sizeof(buf)));
#elif _POSIX_C_SOURCE >= 200112L
int retcode;
// POSIX.1-2001 and POSIX.1-2008
retcode = strerror_r(errnum, buf, sizeof(buf));
#else
#error "Could not find a thread-safe alternative to strerror()."
#endif
#if !defined(_GNU_SOURCE)
if (retcode) {
std::string msg = "unable to get error message for a given error number";
// C++11 would make this shorter with std::to_string()
std::ostringstream ostr;
ostr << errnum;
#if !defined(SG_WINDOWS)
if (retcode == ERANGE) { // more specific error message in this case
msg = std::string("buffer too small to hold the error message for "
"the specified error number");
}
#endif
throw sg_error(msg, ostr.str());
}
return std::string(buf);
#endif // !defined(_GNU_SOURCE)
}
} // end namespace strutils
} // end namespace simgear

View File

@@ -216,6 +216,14 @@ namespace simgear {
*/
std::string sanitizePrintfFormat(const std::string& input);
/**
* Get the message corresponding to a given value of errno.
*
* Similar to strerror(), except it should be thread-safe and returns an
* std::string.
*/
std::string error_string(int errnum);
} // end namespace strutils
} // end namespace simgear

View File

@@ -2,6 +2,9 @@
#define BOOST_TEST_MODULE misc
#include <BoostTestTargetConfig.h>
#include <errno.h>
#include <stdlib.h> // _set_errno() on Windows
#include <fstream> // std::ifstream
#include <simgear/compiler.h>
#include "strutils.hxx"
@@ -78,3 +81,24 @@ BOOST_AUTO_TEST_CASE( md5_hex )
// md5
BOOST_CHECK_EQUAL(strutils::md5("test"), "098f6bcd4621d373cade4e832627b4f6");
}
BOOST_AUTO_TEST_CASE( error_string )
{
#if defined(SG_WINDOWS)
_set_errno(0);
#else
errno = 0;
#endif
std::ifstream f("/\\/non-existent/file/a8f7bz97-3ffe-4f5b-b8db-38ccurJL-");
#if defined(SG_WINDOWS)
errno_t saved_errno = errno;
#else
int saved_errno = errno;
#endif
BOOST_CHECK(!f.is_open());
BOOST_CHECK_NE(saved_errno, 0);
BOOST_CHECK_GT(strutils::error_string(saved_errno).size(), 0);
}