Move OS-specific APIs to a separate header
This commit is contained in:
+1
-2
@@ -1503,8 +1503,7 @@ FMT_API void vprint(string_view format_str, format_args args);
|
||||
/**
|
||||
\rst
|
||||
Prints formatted data to the file *f*. For wide format strings,
|
||||
*f* should be in wide-oriented mode set via ``fwide(f, 1)`` or
|
||||
``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
|
||||
*f* should be in wide-oriented mode set via ``fwide(f, 1)``.
|
||||
|
||||
**Example**::
|
||||
|
||||
|
||||
+8
-110
@@ -21,27 +21,6 @@
|
||||
# include <locale>
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
|
||||
# include <windows.h>
|
||||
# else
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
# undef NOMINMAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_EXCEPTIONS
|
||||
# define FMT_TRY try
|
||||
# define FMT_CATCH(x) catch (x)
|
||||
#else
|
||||
# define FMT_TRY if (true)
|
||||
# define FMT_CATCH(x) if (false)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4702) // unreachable code
|
||||
@@ -73,8 +52,6 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||
# define FMT_SNPRINTF fmt_snprintf
|
||||
#endif // _MSC_VER
|
||||
|
||||
using format_func = void (*)(internal::buffer<char>&, int, string_view);
|
||||
|
||||
// A portable thread-safe version of strerror.
|
||||
// Sets buffer to point to a string describing the error code.
|
||||
// This can be either a pointer to a string stored in buffer,
|
||||
@@ -168,15 +145,6 @@ FMT_FUNC void format_error_code(internal::buffer<char>& out, int error_code,
|
||||
assert(out.size() <= inline_buffer_size);
|
||||
}
|
||||
|
||||
// A wrapper around fwrite that throws on error.
|
||||
FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
|
||||
FILE* stream) {
|
||||
size_t written = std::fwrite(ptr, size, count, stream);
|
||||
if (written < count) {
|
||||
FMT_THROW(system_error(errno, "cannot write to file"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC void report_error(format_func func, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
memory_buffer full_message;
|
||||
@@ -185,6 +153,14 @@ FMT_FUNC void report_error(format_func func, int error_code,
|
||||
(void)std::fwrite(full_message.data(), full_message.size(), 1, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
}
|
||||
|
||||
// A wrapper around fwrite that throws on error.
|
||||
FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
|
||||
FILE* stream) {
|
||||
size_t written = std::fwrite(ptr, size, count, stream);
|
||||
if (written < count)
|
||||
FMT_THROW(system_error(errno, "cannot write to file"));
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
@@ -1312,77 +1288,6 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
buffer_.push_back(0);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||
if (int error_code = convert(s)) {
|
||||
FMT_THROW(windows_error(error_code,
|
||||
"cannot convert string from UTF-16 to UTF-8"));
|
||||
}
|
||||
}
|
||||
|
||||
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
|
||||
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
|
||||
int s_size = static_cast<int>(s.size());
|
||||
if (s_size == 0) {
|
||||
// WideCharToMultiByte does not support zero length, handle separately.
|
||||
buffer_.resize(1);
|
||||
buffer_[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
|
||||
nullptr, nullptr);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_.resize(length + 1);
|
||||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
||||
length, nullptr, nullptr);
|
||||
if (length == 0) return GetLastError();
|
||||
buffer_[length] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void windows_error::init(int err_code, string_view format_str,
|
||||
format_args args) {
|
||||
error_code_ = err_code;
|
||||
memory_buffer buffer;
|
||||
internal::format_windows_error(buffer, err_code, vformat(format_str, args));
|
||||
std::runtime_error& base = *this;
|
||||
base = std::runtime_error(to_string(buffer));
|
||||
}
|
||||
|
||||
FMT_FUNC void internal::format_windows_error(internal::buffer<char>& out,
|
||||
int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
wmemory_buffer buf;
|
||||
buf.resize(inline_buffer_size);
|
||||
for (;;) {
|
||||
wchar_t* system_message = &buf[0];
|
||||
int result = FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
|
||||
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
|
||||
static_cast<uint32_t>(buf.size()), nullptr);
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
internal::writer w(out);
|
||||
w.write(message);
|
||||
w.write(": ");
|
||||
w.write(utf8_message);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
break; // Can't get error message, report error code instead.
|
||||
buf.resize(buf.size() * 2);
|
||||
}
|
||||
}
|
||||
FMT_CATCH(...) {}
|
||||
format_error_code(out, error_code, message);
|
||||
}
|
||||
#endif // FMT_USE_WINDOWS_H
|
||||
|
||||
FMT_FUNC void format_system_error(internal::buffer<char>& out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT {
|
||||
FMT_TRY {
|
||||
@@ -1417,13 +1322,6 @@ FMT_FUNC void report_system_error(int error_code,
|
||||
report_error(format_system_error, error_code, message);
|
||||
}
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
FMT_FUNC void report_windows_error(int error_code,
|
||||
fmt::string_view message) FMT_NOEXCEPT {
|
||||
report_error(internal::format_windows_error, error_code, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
|
||||
memory_buffer buffer;
|
||||
internal::vformat_to(buffer, format_str,
|
||||
|
||||
+30
-96
@@ -69,7 +69,7 @@
|
||||
# define FMT_HAS_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
#if __cplusplus == 201103L || __cplusplus == 201402L
|
||||
#if __cplusplus == 201103L || __cplusplus == 201402L
|
||||
# if defined(__clang__)
|
||||
# define FMT_FALLTHROUGH [[clang::fallthrough]]
|
||||
# elif FMT_GCC_VERSION >= 700
|
||||
@@ -78,7 +78,7 @@
|
||||
# define FMT_FALLTHROUGH
|
||||
# endif
|
||||
#elif (FMT_HAS_CPP_ATTRIBUTE(fallthrough) && (__cplusplus >= 201703)) || \
|
||||
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
# define FMT_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
# define FMT_FALLTHROUGH
|
||||
@@ -110,6 +110,14 @@ FMT_END_NAMESPACE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if FMT_EXCEPTIONS
|
||||
# define FMT_TRY try
|
||||
# define FMT_CATCH(x) catch (x)
|
||||
#else
|
||||
# define FMT_TRY if (true)
|
||||
# define FMT_CATCH(x) if (false)
|
||||
#endif
|
||||
|
||||
#ifndef FMT_USE_USER_DEFINED_LITERALS
|
||||
// For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs.
|
||||
# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
|
||||
@@ -953,39 +961,6 @@ class utf8_to_utf16 {
|
||||
std::wstring str() const { return {&buffer_[0], size()}; }
|
||||
};
|
||||
|
||||
// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
|
||||
// All the functionality that relies on it will be disabled too.
|
||||
#ifndef _WIN32
|
||||
# define FMT_USE_WINDOWS_H 0
|
||||
#elif !defined(FMT_USE_WINDOWS_H)
|
||||
# define FMT_USE_WINDOWS_H 1
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
// A converter from UTF-16 to UTF-8.
|
||||
// It is only provided for Windows since other systems support UTF-8 natively.
|
||||
class utf16_to_utf8 {
|
||||
private:
|
||||
memory_buffer buffer_;
|
||||
|
||||
public:
|
||||
utf16_to_utf8() {}
|
||||
FMT_API explicit utf16_to_utf8(wstring_view s);
|
||||
operator string_view() const { return string_view(&buffer_[0], size()); }
|
||||
size_t size() const { return buffer_.size() - 1; }
|
||||
const char* c_str() const { return &buffer_[0]; }
|
||||
std::string str() const { return std::string(&buffer_[0], size()); }
|
||||
|
||||
// Performs conversion returning a system error code instead of
|
||||
// throwing exception on conversion error. This method may still throw
|
||||
// in case of memory allocation error.
|
||||
FMT_API int convert(wstring_view s);
|
||||
};
|
||||
|
||||
FMT_API void format_windows_error(internal::buffer<char>& out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
template <typename T = void> struct null {};
|
||||
|
||||
// Workaround an array initialization issue in gcc 4.8.
|
||||
@@ -2660,6 +2635,14 @@ void handle_dynamic_spec(int& value, arg_ref<typename Context::char_type> ref,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
using format_func = void (*)(internal::buffer<char>&, int, string_view);
|
||||
|
||||
FMT_API void format_error_code(buffer<char>& out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
|
||||
FMT_API void report_error(format_func func, int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
} // namespace internal
|
||||
|
||||
template <typename Range>
|
||||
@@ -2779,55 +2762,6 @@ FMT_API void format_system_error(internal::buffer<char>& out, int error_code,
|
||||
FMT_API void report_system_error(int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
|
||||
/** A Windows error. */
|
||||
class windows_error : public system_error {
|
||||
private:
|
||||
FMT_API void init(int error_code, string_view format_str, format_args args);
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a :class:`fmt::windows_error` object with the description
|
||||
of the form
|
||||
|
||||
.. parsed-literal::
|
||||
*<message>*: *<system-message>*
|
||||
|
||||
where *<message>* is the formatted message and *<system-message>* is the
|
||||
system message corresponding to the error code.
|
||||
*error_code* is a Windows error code as given by ``GetLastError``.
|
||||
If *error_code* is not a valid error code such as -1, the system message
|
||||
will look like "error -1".
|
||||
|
||||
**Example**::
|
||||
|
||||
// This throws a windows_error with the description
|
||||
// cannot open file 'madeup': The system cannot find the file specified.
|
||||
// or similar (system message may vary).
|
||||
const char *filename = "madeup";
|
||||
LPOFSTRUCT of = LPOFSTRUCT();
|
||||
HFILE file = OpenFile(filename, &of, OF_READ);
|
||||
if (file == HFILE_ERROR) {
|
||||
throw fmt::windows_error(GetLastError(),
|
||||
"cannot open file '{}'", filename);
|
||||
}
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
windows_error(int error_code, string_view message, const Args&... args) {
|
||||
init(error_code, message, make_format_args(args...));
|
||||
}
|
||||
};
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
|
||||
#endif
|
||||
|
||||
/** Fast integer formatter. */
|
||||
class format_int {
|
||||
private:
|
||||
@@ -3513,18 +3447,18 @@ FMT_CONSTEXPR internal::udl_arg<wchar_t> operator"" _a(const wchar_t* s,
|
||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#define FMT_STRING_IMPL(s, ...) \
|
||||
[] { \
|
||||
/* Use a macro-like name to avoid shadowing warnings. */ \
|
||||
struct FMT_STRING : fmt::compile_string { \
|
||||
using char_type = typename std::remove_cv<std::remove_pointer< \
|
||||
typename std::decay<decltype(s)>::type>::type>::type; \
|
||||
__VA_ARGS__ FMT_CONSTEXPR \
|
||||
operator fmt::basic_string_view<char_type>() const { \
|
||||
return {s, sizeof(s) / sizeof(char_type) - 1}; \
|
||||
} \
|
||||
}; \
|
||||
return FMT_STRING(); \
|
||||
#define FMT_STRING_IMPL(s, ...) \
|
||||
[] { \
|
||||
/* Use a macro-like name to avoid shadowing warnings. */ \
|
||||
struct FMT_STRING : fmt::compile_string { \
|
||||
using char_type = typename std::remove_cv<std::remove_pointer< \
|
||||
typename std::decay<decltype(s)>::type>::type>::type; \
|
||||
__VA_ARGS__ FMT_CONSTEXPR \
|
||||
operator fmt::basic_string_view<char_type>() const { \
|
||||
return {s, sizeof(s) / sizeof(char_type) - 1}; \
|
||||
} \
|
||||
}; \
|
||||
return FMT_STRING(); \
|
||||
}()
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// Formatting library for C++ - optional OS-specific functionality
|
||||
//
|
||||
// Copyright (c) 2012 - present, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#ifndef FMT_OS_H_
|
||||
#define FMT_OS_H_
|
||||
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
|
||||
// All the functionality that relies on it will be disabled too.
|
||||
#ifndef _WIN32
|
||||
# define FMT_USE_WINDOWS_H 0
|
||||
#elif !defined(FMT_USE_WINDOWS_H)
|
||||
# define FMT_USE_WINDOWS_H 1
|
||||
#endif
|
||||
|
||||
#if FMT_USE_WINDOWS_H
|
||||
namespace internal {
|
||||
// A converter from UTF-16 to UTF-8.
|
||||
// It is only provided for Windows since other systems support UTF-8 natively.
|
||||
class utf16_to_utf8 {
|
||||
private:
|
||||
memory_buffer buffer_;
|
||||
|
||||
public:
|
||||
utf16_to_utf8() {}
|
||||
FMT_API explicit utf16_to_utf8(wstring_view s);
|
||||
operator string_view() const { return string_view(&buffer_[0], size()); }
|
||||
size_t size() const { return buffer_.size() - 1; }
|
||||
const char* c_str() const { return &buffer_[0]; }
|
||||
std::string str() const { return std::string(&buffer_[0], size()); }
|
||||
|
||||
// Performs conversion returning a system error code instead of
|
||||
// throwing exception on conversion error. This method may still throw
|
||||
// in case of memory allocation error.
|
||||
FMT_API int convert(wstring_view s);
|
||||
};
|
||||
|
||||
FMT_API void format_windows_error(internal::buffer<char>& out, int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
} // namespace internal
|
||||
|
||||
/** A Windows error. */
|
||||
class windows_error : public system_error {
|
||||
private:
|
||||
FMT_API void init(int error_code, string_view format_str, format_args args);
|
||||
|
||||
public:
|
||||
/**
|
||||
\rst
|
||||
Constructs a :class:`fmt::windows_error` object with the description
|
||||
of the form
|
||||
|
||||
.. parsed-literal::
|
||||
*<message>*: *<system-message>*
|
||||
|
||||
where *<message>* is the formatted message and *<system-message>* is the
|
||||
system message corresponding to the error code.
|
||||
*error_code* is a Windows error code as given by ``GetLastError``.
|
||||
If *error_code* is not a valid error code such as -1, the system message
|
||||
will look like "error -1".
|
||||
|
||||
**Example**::
|
||||
|
||||
// This throws a windows_error with the description
|
||||
// cannot open file 'madeup': The system cannot find the file specified.
|
||||
// or similar (system message may vary).
|
||||
const char *filename = "madeup";
|
||||
LPOFSTRUCT of = LPOFSTRUCT();
|
||||
HFILE file = OpenFile(filename, &of, OF_READ);
|
||||
if (file == HFILE_ERROR) {
|
||||
throw fmt::windows_error(GetLastError(),
|
||||
"cannot open file '{}'", filename);
|
||||
}
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args>
|
||||
windows_error(int error_code, string_view message, const Args&... args) {
|
||||
init(error_code, message, make_format_args(args...));
|
||||
}
|
||||
};
|
||||
|
||||
// Reports a Windows error without throwing an exception.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_windows_error(int error_code,
|
||||
string_view message) FMT_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_OS_H_
|
||||
Reference in New Issue
Block a user