Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
fmt
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
fmt
Commits
35959a31
Commit
35959a31
authored
Dec 15, 2019
by
Victor Zverovich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move OS-specific APIs to a separate header
parent
ec2463c9
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
381 additions
and
370 deletions
+381
-370
CMakeLists.txt
CMakeLists.txt
+1
-1
include/fmt/core.h
include/fmt/core.h
+1
-2
include/fmt/format-inl.h
include/fmt/format-inl.h
+8
-110
include/fmt/format.h
include/fmt/format.h
+30
-96
include/fmt/os.h
include/fmt/os.h
+97
-0
src/posix.cc
src/posix.cc
+115
-35
test/format-test.cc
test/format-test.cc
+12
-126
test/posix-test.cc
test/posix-test.cc
+117
-0
No files found.
CMakeLists.txt
View file @
35959a31
...
...
@@ -151,7 +151,7 @@ endfunction()
# Define the fmt library, its includes and the needed defines.
add_headers
(
FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
locale.h ostream.h posix.h printf.h ranges.h
)
locale.h os
.h os
tream.h posix.h printf.h ranges.h
)
set
(
FMT_SOURCES src/format.cc src/posix.cc
)
add_library
(
fmt
${
FMT_SOURCES
}
${
FMT_HEADERS
}
README.rst ChangeLog.rst
)
...
...
include/fmt/core.h
View file @
35959a31
...
...
@@ -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**::
...
...
include/fmt/format-inl.h
View file @
35959a31
...
...
@@ -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
,
...
...
include/fmt/format.h
View file @
35959a31
...
...
@@ -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(); \
}()
/**
...
...
include/fmt/os.h
0 → 100644
View file @
35959a31
// 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_
src/posix.cc
View file @
35959a31
...
...
@@ -11,38 +11,43 @@
#endif
#include "fmt/posix.h"
#include "fmt/os.h"
#include <climits>
#if FMT_USE_FCNTL
#include <sys/stat.h>
#include <sys/types.h>
#
include <sys/stat.h>
#
include <sys/types.h>
#ifndef _WIN32
# include <unistd.h>
#else
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <io.h>
# include <windows.h>
#
ifndef _WIN32
#
include <unistd.h>
#
else
#
ifndef WIN32_LEAN_AND_MEAN
#
define WIN32_LEAN_AND_MEAN
#
endif
#
include <io.h>
#
include <windows.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
#
define O_CREAT _O_CREAT
#
define O_TRUNC _O_TRUNC
# ifndef S_IRUSR
# define S_IRUSR _S_IREAD
# endif
#
ifndef S_IRUSR
#
define S_IRUSR _S_IREAD
#
endif
# ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
# endif
#
ifndef S_IWUSR
#
define S_IWUSR _S_IWRITE
#
endif
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# endif
#endif // _WIN32
#endif // FMT_USE_FCNTL
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# endif
# endif // _WIN32
#endif // FMT_USE_FCNTL
#if FMT_USE_WINDOWS_H
# include <windows.h>
#endif
#ifdef fileno
# undef fileno
...
...
@@ -68,6 +73,81 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
FMT_BEGIN_NAMESPACE
#if FMT_USE_WINDOWS_H
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"
));
}
}
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
;
}
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
));
}
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
);
}
void
report_windows_error
(
int
error_code
,
fmt
::
string_view
message
)
FMT_NOEXCEPT
{
report_error
(
internal
::
format_windows_error
,
error_code
,
message
);
}
#endif // FMT_USE_WINDOWS_H
buffered_file
::~
buffered_file
()
FMT_NOEXCEPT
{
if
(
file_
&&
FMT_SYSTEM
(
fclose
(
file_
))
!=
0
)
report_system_error
(
errno
,
"cannot close file"
);
...
...
@@ -99,12 +179,12 @@ int buffered_file::fileno() const {
#if FMT_USE_FCNTL
file
::
file
(
cstring_view
path
,
int
oflag
)
{
int
mode
=
S_IRUSR
|
S_IWUSR
;
#if defined(_WIN32) && !defined(__MINGW32__)
#
if defined(_WIN32) && !defined(__MINGW32__)
fd_
=
-
1
;
FMT_POSIX_CALL
(
sopen_s
(
&
fd_
,
path
.
c_str
(),
oflag
,
_SH_DENYNO
,
mode
));
#else
#
else
FMT_RETRY
(
fd_
,
FMT_POSIX_CALL
(
open
(
path
.
c_str
(),
oflag
,
mode
)));
#endif
#
endif
if
(
fd_
==
-
1
)
FMT_THROW
(
system_error
(
errno
,
"cannot open file {}"
,
path
.
c_str
()));
}
...
...
@@ -126,7 +206,7 @@ void file::close() {
}
long
long
file
::
size
()
const
{
#ifdef _WIN32
#
ifdef _WIN32
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
// is less than 0x0500 as is the case with some default MinGW builds.
// Both functions support large file sizes.
...
...
@@ -140,7 +220,7 @@ long long file::size() const {
}
unsigned
long
long
long_size
=
size_upper
;
return
(
long_size
<<
sizeof
(
DWORD
)
*
CHAR_BIT
)
|
size_lower
;
#else
#
else
using
Stat
=
struct
stat
;
Stat
file_stat
=
Stat
();
if
(
FMT_POSIX_CALL
(
fstat
(
fd_
,
&
file_stat
))
==
-
1
)
...
...
@@ -148,7 +228,7 @@ long long file::size() const {
static_assert
(
sizeof
(
long
long
)
>=
sizeof
(
file_stat
.
st_size
),
"return type of file::size is not large enough"
);
return
file_stat
.
st_size
;
#endif
#
endif
}
std
::
size_t
file
::
read
(
void
*
buffer
,
std
::
size_t
count
)
{
...
...
@@ -195,15 +275,15 @@ void file::pipe(file& read_end, file& write_end) {
read_end
.
close
();
write_end
.
close
();
int
fds
[
2
]
=
{};
#ifdef _WIN32
#
ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum
{
DEFAULT_CAPACITY
=
65536
};
int
result
=
FMT_POSIX_CALL
(
pipe
(
fds
,
DEFAULT_CAPACITY
,
_O_BINARY
));
#else
#
else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int
result
=
FMT_POSIX_CALL
(
pipe
(
fds
));
#endif
#
endif
if
(
result
!=
0
)
FMT_THROW
(
system_error
(
errno
,
"cannot create pipe"
));
// The following assignments don't throw because read_fd and write_fd
// are closed.
...
...
@@ -223,15 +303,15 @@ buffered_file file::fdopen(const char* mode) {
}
long
getpagesize
()
{
#ifdef _WIN32
#
ifdef _WIN32
SYSTEM_INFO
si
;
GetSystemInfo
(
&
si
);
return
si
.
dwPageSize
;
#else
#
else
long
size
=
FMT_POSIX_CALL
(
sysconf
(
_SC_PAGESIZE
));
if
(
size
<
0
)
FMT_THROW
(
system_error
(
errno
,
"cannot get memory page size"
));
return
size
;
#endif
#
endif
}
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE
test/format-test.cc
View file @
35959a31
...
...
@@ -417,67 +417,6 @@ TEST(UtilTest, UTF8ToUTF16EmptyString) {
EXPECT_EQ
(
s
.
size
(),
u
.
size
());
}
#ifdef _WIN32
TEST
(
UtilTest
,
UTF16ToUTF8
)
{
std
::
string
s
=
"ёжик"
;
fmt
::
internal
::
utf16_to_utf8
u
(
L"
\x0451\x0436\x0438\x043A
"
);
EXPECT_EQ
(
s
,
u
.
str
());
EXPECT_EQ
(
s
.
size
(),
u
.
size
());
}
TEST
(
UtilTest
,
UTF16ToUTF8EmptyString
)
{
std
::
string
s
=
""
;
fmt
::
internal
::
utf16_to_utf8
u
(
L""
);
EXPECT_EQ
(
s
,
u
.
str
());
EXPECT_EQ
(
s
.
size
(),
u
.
size
());
}
template
<
typename
Converter
,
typename
Char
>
void
check_utf_conversion_error
(
const
char
*
message
,
fmt
::
basic_string_view
<
Char
>
str
=
fmt
::
basic_string_view
<
Char
>
(
0
,
1
))
{
fmt
::
memory_buffer
out
;
fmt
::
internal
::
format_windows_error
(
out
,
ERROR_INVALID_PARAMETER
,
message
);
fmt
::
system_error
error
(
0
,
""
);
try
{
(
Converter
)(
str
);
}
catch
(
const
fmt
::
system_error
&
e
)
{
error
=
e
;
}
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
error
.
error_code
());
EXPECT_EQ
(
fmt
::
to_string
(
out
),
error
.
what
());
}
TEST
(
UtilTest
,
UTF16ToUTF8Error
)
{
check_utf_conversion_error
<
fmt
::
internal
::
utf16_to_utf8
,
wchar_t
>
(
"cannot convert string from UTF-16 to UTF-8"
);
}
TEST
(
UtilTest
,
UTF16ToUTF8Convert
)
{
fmt
::
internal
::
utf16_to_utf8
u
;
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
u
.
convert
(
fmt
::
wstring_view
(
0
,
1
)));
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
u
.
convert
(
fmt
::
wstring_view
(
L"foo"
,
INT_MAX
+
1u
)));
}
#endif // _WIN32
typedef
void
(
*
FormatErrorMessage
)(
fmt
::
internal
::
buffer
<
char
>&
out
,
int
error_code
,
string_view
message
);
template
<
typename
Error
>
void
check_throw_error
(
int
error_code
,
FormatErrorMessage
format
)
{
fmt
::
system_error
error
(
0
,
""
);
try
{
throw
Error
(
error_code
,
"test {}"
,
"error"
);
}
catch
(
const
fmt
::
system_error
&
e
)
{
error
=
e
;
}
fmt
::
memory_buffer
message
;
format
(
message
,
error_code
,
"test error"
);
EXPECT_EQ
(
to_string
(
message
),
error
.
what
());
EXPECT_EQ
(
error_code
,
error
.
error_code
());
}
TEST
(
UtilTest
,
FormatSystemError
)
{
fmt
::
memory_buffer
message
;
fmt
::
format_system_error
(
message
,
EDOM
,
"test"
);
...
...
@@ -506,7 +445,17 @@ TEST(UtilTest, SystemError) {
fmt
::
system_error
e
(
EDOM
,
"test"
);
EXPECT_EQ
(
fmt
::
format
(
"test: {}"
,
get_system_error
(
EDOM
)),
e
.
what
());
EXPECT_EQ
(
EDOM
,
e
.
error_code
());
check_throw_error
<
fmt
::
system_error
>
(
EDOM
,
fmt
::
format_system_error
);
fmt
::
system_error
error
(
0
,
""
);
try
{
throw
fmt
::
system_error
(
EDOM
,
"test {}"
,
"error"
);
}
catch
(
const
fmt
::
system_error
&
e
)
{
error
=
e
;
}
fmt
::
memory_buffer
message
;
fmt
::
format_system_error
(
message
,
EDOM
,
"test error"
);
EXPECT_EQ
(
to_string
(
message
),
error
.
what
());
EXPECT_EQ
(
EDOM
,
error
.
error_code
());
}
TEST
(
UtilTest
,
ReportSystemError
)
{
...
...
@@ -517,69 +466,6 @@ TEST(UtilTest, ReportSystemError) {
to_string
(
out
));
}
#ifdef _WIN32
TEST
(
UtilTest
,
FormatWindowsError
)
{
LPWSTR
message
=
0
;
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
0
,
ERROR_FILE_EXISTS
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
reinterpret_cast
<
LPWSTR
>
(
&
message
),
0
,
0
);
fmt
::
internal
::
utf16_to_utf8
utf8_message
(
message
);
LocalFree
(
message
);
fmt
::
memory_buffer
actual_message
;
fmt
::
internal
::
format_windows_error
(
actual_message
,
ERROR_FILE_EXISTS
,
"test"
);
EXPECT_EQ
(
fmt
::
format
(
"test: {}"
,
utf8_message
.
str
()),
fmt
::
to_string
(
actual_message
));
actual_message
.
resize
(
0
);
fmt
::
internal
::
format_windows_error
(
actual_message
,
ERROR_FILE_EXISTS
,
fmt
::
string_view
(
0
,
max_value
<
size_t
>
()));
EXPECT_EQ
(
fmt
::
format
(
"error {}"
,
ERROR_FILE_EXISTS
),
fmt
::
to_string
(
actual_message
));
}
TEST
(
UtilTest
,
FormatLongWindowsError
)
{
LPWSTR
message
=
0
;
// this error code is not available on all Windows platforms and
// Windows SDKs, so do not fail the test if the error string cannot
// be retrieved.
const
int
provisioning_not_allowed
=
0x80284013L
/*TBS_E_PROVISIONING_NOT_ALLOWED*/
;
if
(
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
0
,
static_cast
<
DWORD
>
(
provisioning_not_allowed
),
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
reinterpret_cast
<
LPWSTR
>
(
&
message
),
0
,
0
)
==
0
)
{
return
;
}
fmt
::
internal
::
utf16_to_utf8
utf8_message
(
message
);
LocalFree
(
message
);
fmt
::
memory_buffer
actual_message
;
fmt
::
internal
::
format_windows_error
(
actual_message
,
provisioning_not_allowed
,
"test"
);
EXPECT_EQ
(
fmt
::
format
(
"test: {}"
,
utf8_message
.
str
()),
fmt
::
to_string
(
actual_message
));
}
TEST
(
UtilTest
,
WindowsError
)
{
check_throw_error
<
fmt
::
windows_error
>
(
ERROR_FILE_EXISTS
,
fmt
::
internal
::
format_windows_error
);
}
TEST
(
UtilTest
,
ReportWindowsError
)
{
fmt
::
memory_buffer
out
;
fmt
::
internal
::
format_windows_error
(
out
,
ERROR_FILE_EXISTS
,
"test error"
);
out
.
push_back
(
'\n'
);
EXPECT_WRITE
(
stderr
,
fmt
::
report_windows_error
(
ERROR_FILE_EXISTS
,
"test error"
),
fmt
::
to_string
(
out
));
}
#endif // _WIN32
TEST
(
StringViewTest
,
Ctor
)
{
EXPECT_STREQ
(
"abc"
,
string_view
(
"abc"
).
data
());
EXPECT_EQ
(
3u
,
string_view
(
"abc"
).
size
());
...
...
@@ -2611,7 +2497,7 @@ TEST(FormatTest, FormatU8String) {
}
TEST
(
FormatTest
,
EmphasisNonHeaderOnly
)
{
//
e
nsure this compiles even if FMT_HEADER_ONLY is not defined.
//
E
nsure this compiles even if FMT_HEADER_ONLY is not defined.
EXPECT_EQ
(
fmt
::
format
(
fmt
::
emphasis
::
bold
,
"bold error"
),
"
\x1b
[1mbold error
\x1b
[0m"
);
}
...
...
test/posix-test.cc
View file @
35959a31
...
...
@@ -9,6 +9,7 @@
#include <cstring>
#include <memory>
#include "fmt/os.h"
#include "fmt/posix.h"
#include "gtest-extra.h"
#include "util.h"
...
...
@@ -20,6 +21,122 @@
using
fmt
::
buffered_file
;
using
fmt
::
error_code
;
#ifdef _WIN32
#include <windows.h>
TEST
(
UtilTest
,
UTF16ToUTF8
)
{
std
::
string
s
=
"ёжик"
;
fmt
::
internal
::
utf16_to_utf8
u
(
L"
\x0451\x0436\x0438\x043A
"
);
EXPECT_EQ
(
s
,
u
.
str
());
EXPECT_EQ
(
s
.
size
(),
u
.
size
());
}
TEST
(
UtilTest
,
UTF16ToUTF8EmptyString
)
{
std
::
string
s
=
""
;
fmt
::
internal
::
utf16_to_utf8
u
(
L""
);
EXPECT_EQ
(
s
,
u
.
str
());
EXPECT_EQ
(
s
.
size
(),
u
.
size
());
}
template
<
typename
Converter
,
typename
Char
>
void
check_utf_conversion_error
(
const
char
*
message
,
fmt
::
basic_string_view
<
Char
>
str
=
fmt
::
basic_string_view
<
Char
>
(
0
,
1
))
{
fmt
::
memory_buffer
out
;
fmt
::
internal
::
format_windows_error
(
out
,
ERROR_INVALID_PARAMETER
,
message
);
fmt
::
system_error
error
(
0
,
""
);
try
{
(
Converter
)(
str
);
}
catch
(
const
fmt
::
system_error
&
e
)
{
error
=
e
;
}
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
error
.
error_code
());
EXPECT_EQ
(
fmt
::
to_string
(
out
),
error
.
what
());
}
TEST
(
UtilTest
,
UTF16ToUTF8Error
)
{
check_utf_conversion_error
<
fmt
::
internal
::
utf16_to_utf8
,
wchar_t
>
(
"cannot convert string from UTF-16 to UTF-8"
);
}
TEST
(
UtilTest
,
UTF16ToUTF8Convert
)
{
fmt
::
internal
::
utf16_to_utf8
u
;
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
u
.
convert
(
fmt
::
wstring_view
(
0
,
1
)));
EXPECT_EQ
(
ERROR_INVALID_PARAMETER
,
u
.
convert
(
fmt
::
wstring_view
(
L"foo"
,
INT_MAX
+
1u
)));
}
TEST
(
UtilTest
,
FormatWindowsError
)
{
LPWSTR
message
=
0
;
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
0
,
ERROR_FILE_EXISTS
,
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
reinterpret_cast
<
LPWSTR
>
(
&
message
),
0
,
0
);
fmt
::
internal
::
utf16_to_utf8
utf8_message
(
message
);
LocalFree
(
message
);
fmt
::
memory_buffer
actual_message
;
fmt
::
internal
::
format_windows_error
(
actual_message
,
ERROR_FILE_EXISTS
,
"test"
);
EXPECT_EQ
(
fmt
::
format
(
"test: {}"
,
utf8_message
.
str
()),
fmt
::
to_string
(
actual_message
));
actual_message
.
resize
(
0
);
auto
max_size
=
fmt
::
internal
::
max_value
<
size_t
>
();
fmt
::
internal
::
format_windows_error
(
actual_message
,
ERROR_FILE_EXISTS
,
fmt
::
string_view
(
0
,
max_size
));
EXPECT_EQ
(
fmt
::
format
(
"error {}"
,
ERROR_FILE_EXISTS
),
fmt
::
to_string
(
actual_message
));
}
TEST
(
UtilTest
,
FormatLongWindowsError
)
{
LPWSTR
message
=
0
;
// this error code is not available on all Windows platforms and
// Windows SDKs, so do not fail the test if the error string cannot
// be retrieved.
const
int
provisioning_not_allowed
=
0x80284013L
/*TBS_E_PROVISIONING_NOT_ALLOWED*/
;
if
(
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
0
,
static_cast
<
DWORD
>
(
provisioning_not_allowed
),
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
reinterpret_cast
<
LPWSTR
>
(
&
message
),
0
,
0
)
==
0
)
{
return
;
}
fmt
::
internal
::
utf16_to_utf8
utf8_message
(
message
);
LocalFree
(
message
);
fmt
::
memory_buffer
actual_message
;
fmt
::
internal
::
format_windows_error
(
actual_message
,
provisioning_not_allowed
,
"test"
);
EXPECT_EQ
(
fmt
::
format
(
"test: {}"
,
utf8_message
.
str
()),
fmt
::
to_string
(
actual_message
));
}
TEST
(
UtilTest
,
WindowsError
)
{
fmt
::
system_error
error
(
0
,
""
);
try
{
throw
fmt
::
windows_error
(
ERROR_FILE_EXISTS
,
"test {}"
,
"error"
);
}
catch
(
const
fmt
::
system_error
&
e
)
{
error
=
e
;
}
fmt
::
memory_buffer
message
;
fmt
::
internal
::
format_windows_error
(
message
,
ERROR_FILE_EXISTS
,
"test error"
);
EXPECT_EQ
(
to_string
(
message
),
error
.
what
());
EXPECT_EQ
(
ERROR_FILE_EXISTS
,
error
.
error_code
());
}
TEST
(
UtilTest
,
ReportWindowsError
)
{
fmt
::
memory_buffer
out
;
fmt
::
internal
::
format_windows_error
(
out
,
ERROR_FILE_EXISTS
,
"test error"
);
out
.
push_back
(
'\n'
);
EXPECT_WRITE
(
stderr
,
fmt
::
report_windows_error
(
ERROR_FILE_EXISTS
,
"test error"
),
fmt
::
to_string
(
out
));
}
#endif // _WIN32
#if FMT_USE_FCNTL
using
fmt
::
file
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment