diff --git a/CMakeLists.txt b/CMakeLists.txt index 12b65148..fe2ab6a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,18 @@ if (FMT_SHARED) set(shared SHARED) endif () -add_library(format ${shared} format.cc format.h) +include(CheckSymbolExists) +if (WIN32) + check_symbol_exists(open io.h HAVE_OPEN) +else () + check_symbol_exists(open fcntl.h HAVE_OPEN) +endif () +if (HAVE_OPEN) + add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1) + set(FMT_POSIX_SRC posix.cc posix.h) +endif () + +add_library(format ${shared} format.cc format.h ${FMT_POSIX_SRC}) if (CMAKE_COMPILER_IS_GNUCXX) set_target_properties(format PROPERTIES COMPILE_FLAGS "-Wall -Wextra -pedantic") @@ -55,7 +66,7 @@ if (CPP11_FLAG AND FMT_EXTRA_TESTS) set_target_properties(format PROPERTIES COMPILE_FLAGS ${CPP11_FLAG}) # Test compilation with default flags. file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} test/*.cc test/*.h) - add_library(testformat format.cc ${src}) + add_library(testformat format.cc ${FMT_POSIX_SRC} ${src}) endif () add_subdirectory(doc) @@ -77,16 +88,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1) endif () -include(CheckSymbolExists) -if (WIN32) - check_symbol_exists(open io.h HAVE_OPEN) -else () - check_symbol_exists(open fcntl.h HAVE_OPEN) -endif () -if (HAVE_OPEN) - add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1) -endif () - enable_testing() include_directories(.) diff --git a/posix.cc b/posix.cc index 9d883603..9c3cc2ca 100644 --- a/posix.cc +++ b/posix.cc @@ -27,7 +27,6 @@ #include "posix.h" -#include #include #include #include @@ -44,16 +43,6 @@ #endif // _WIN32 -// Retries the expression while it evaluates to -1 and error equals to EINTR. -#ifndef _WIN32 -# define FMT_RETRY(result, expression) \ - do { \ - result = (expression); \ - } while (result == -1 && errno == EINTR) -#else -# define FMT_RETRY(result, expression) result = (expression) -#endif - namespace { #ifdef _WIN32 // On Windows the count argument to read and write is unsigned, so convert @@ -66,12 +55,12 @@ inline std::size_t ConvertRWCount(std::size_t count) { return count; } #endif } -BufferedFile::~BufferedFile() FMT_NOEXCEPT(true) { +fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT(true) { if (file_ && FMT_SYSTEM(fclose(file_)) != 0) fmt::ReportSystemError(errno, "cannot close file"); } -void BufferedFile::close() { +void fmt::BufferedFile::close() { if (!file_) return; int result = FMT_SYSTEM(fclose(file_)); @@ -80,14 +69,14 @@ void BufferedFile::close() { fmt::ThrowSystemError(errno, "cannot close file"); } -int BufferedFile::fileno() const { +int fmt::BufferedFile::fileno() const { int fd = FMT_POSIX_CALL(fileno(file_)); if (fd == -1) fmt::ThrowSystemError(errno, "cannot get file descriptor"); return fd; } -File::File(const char *path, int oflag) { +fmt::File::File(const char *path, int oflag) { int mode = S_IRUSR | S_IWUSR; #ifdef _WIN32 fd_ = -1; @@ -99,14 +88,14 @@ File::File(const char *path, int oflag) { fmt::ThrowSystemError(errno, "cannot open file {}") << path; } -File::~File() FMT_NOEXCEPT(true) { +fmt::File::~File() FMT_NOEXCEPT(true) { // Don't retry close in case of EINTR! // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) fmt::ReportSystemError(errno, "cannot close file"); } -void File::close() { +void fmt::File::close() { if (fd_ == -1) return; // Don't retry close in case of EINTR! @@ -117,7 +106,7 @@ void File::close() { fmt::ThrowSystemError(errno, "cannot close file"); } -std::streamsize File::read(void *buffer, std::size_t count) { +std::streamsize fmt::File::read(void *buffer, std::size_t count) { std::streamsize result = 0; FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, ConvertRWCount(count)))); if (result == -1) @@ -125,7 +114,7 @@ std::streamsize File::read(void *buffer, std::size_t count) { return result; } -std::streamsize File::write(const void *buffer, std::size_t count) { +std::streamsize fmt::File::write(const void *buffer, std::size_t count) { std::streamsize result = 0; FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, ConvertRWCount(count)))); if (result == -1) @@ -133,7 +122,7 @@ std::streamsize File::write(const void *buffer, std::size_t count) { return result; } -File File::dup(int fd) { +fmt::File fmt::File::dup(int fd) { // Don't retry as dup doesn't return EINTR. // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html int new_fd = FMT_POSIX_CALL(dup(fd)); @@ -142,7 +131,7 @@ File File::dup(int fd) { return File(new_fd); } -void File::dup2(int fd) { +void fmt::File::dup2(int fd) { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) { @@ -151,14 +140,14 @@ void File::dup2(int fd) { } } -void File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) { +void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) ec = ErrorCode(errno); } -void File::pipe(File &read_end, File &write_end) { +void fmt::File::pipe(File &read_end, File &write_end) { // Close the descriptors first to make sure that assignments don't throw // and there are no leaks. read_end.close(); @@ -181,7 +170,7 @@ void File::pipe(File &read_end, File &write_end) { write_end = File(fds[1]); } -BufferedFile File::fdopen(const char *mode) { +fmt::BufferedFile fmt::File::fdopen(const char *mode) { // Don't retry as fdopen doesn't return EINTR. FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); if (!f) { diff --git a/posix.h b/posix.h index ef495bb0..bff3bb6f 100644 --- a/posix.h +++ b/posix.h @@ -28,12 +28,15 @@ #ifndef FMT_POSIX_H #define FMT_POSIX_H -#include +#include #include +#include #include #include +#include "format.h" + #ifndef FMT_POSIX # ifdef _WIN32 // Fix warnings about deprecated symbols. @@ -56,29 +59,41 @@ # endif #endif +// Retries the expression while it evaluates to -1 and error equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY(result, expression) \ + do { \ + result = (expression); \ + } while (result == -1 && errno == EINTR) +#else +# define FMT_RETRY(result, expression) result = (expression) +#endif + +namespace fmt { + // An error code. class ErrorCode { - private: +private: int value_; - public: - explicit ErrorCode(int value = 0) FMT_NOEXCEPT(true) : value_(value) {} +public: + explicit ErrorCode(int value = 0) FMT_NOEXCEPT(true) : value_(value) { } int get() const FMT_NOEXCEPT(true) { return value_; } }; // A buffered file. class BufferedFile { - private: +private: FILE *file_; friend class File; - explicit BufferedFile(FILE *f) : file_(f) {} + explicit BufferedFile(FILE *f) : file_(f) { } - public: +public: // Constructs a BufferedFile object which doesn't represent any file. - BufferedFile() FMT_NOEXCEPT(true) : file_(0) {} + BufferedFile() FMT_NOEXCEPT(true) : file_(0) { } // Destroys the object closing the file it represents if any. ~BufferedFile() FMT_NOEXCEPT(true); @@ -87,16 +102,16 @@ class BufferedFile { // Emulate a move constructor and a move assignment operator if rvalue // references are not supported. - private: +private: // A proxy object to emulate a move constructor. // It is private to make it impossible call operator Proxy directly. struct Proxy { FILE *file; }; - public: +public: // A "move constructor" for moving from a temporary. - BufferedFile(Proxy p) FMT_NOEXCEPT(true) : file_(p.file) {} + BufferedFile(Proxy p) FMT_NOEXCEPT(true) : file_(p.file) { } // A "move constructor" for for moving from an lvalue. BufferedFile(BufferedFile &f) FMT_NOEXCEPT(true) : file_(f.file_) { @@ -125,6 +140,7 @@ class BufferedFile { file_ = 0; return p; } + #else private: GTEST_DISALLOW_COPY_AND_ASSIGN_(BufferedFile); @@ -158,22 +174,22 @@ class BufferedFile { // than an exception. You can get standard behavior by overriding the // invalid parameter handler with _set_invalid_parameter_handler. class File { - private: +private: int fd_; // File descriptor. // Constructs a File object with a given descriptor. - explicit File(int fd) : fd_(fd) {} + explicit File(int fd) : fd_(fd) { } - public: +public: // Possible values for the oflag argument to the constructor. enum { RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. - RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. + RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. }; // Constructs a File object which doesn't represent any file. - File() FMT_NOEXCEPT(true) : fd_(-1) {} + File() FMT_NOEXCEPT(true) : fd_(-1) { } // Opens a file and constructs a File object representing this file. File(const char *path, int oflag); @@ -182,16 +198,16 @@ class File { // Emulate a move constructor and a move assignment operator if rvalue // references are not supported. - private: +private: // A proxy object to emulate a move constructor. // It is private to make it impossible call operator Proxy directly. struct Proxy { int fd; }; - public: +public: // A "move constructor" for moving from a temporary. - File(Proxy p) FMT_NOEXCEPT(true) : fd_(p.fd) {} + File(Proxy p) FMT_NOEXCEPT(true) : fd_(p.fd) { } // A "move constructor" for for moving from an lvalue. File(File &other) FMT_NOEXCEPT(true) : fd_(other.fd_) { @@ -220,6 +236,7 @@ class File { fd_ = -1; return p; } + #else private: GTEST_DISALLOW_COPY_AND_ASSIGN_(File); @@ -273,11 +290,13 @@ class File { BufferedFile fdopen(const char *mode); }; +} + #if !FMT_USE_RVALUE_REFERENCES namespace std { // For compatibility with C++98. -inline BufferedFile &move(BufferedFile &f) { return f; } -inline File &move(File &f) { return f; } +inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } +inline fmt::File &move(fmt::File &f) { return f; } } #endif diff --git a/test/format-test.cc b/test/format-test.cc index cf0dbb2b..065f0cf8 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1466,6 +1466,9 @@ TEST(FormatterTest, OutputNotWrittenOnError) { #if FMT_USE_FILE_DESCRIPTORS +using fmt::BufferedFile; +using fmt::File; + TEST(FormatterTest, FileSink) { File read_end, write_end; File::pipe(read_end, write_end); diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index b2d9ce82..5d5c678b 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -356,6 +356,10 @@ TEST(UtilTest, FormatSystemErrorMessage) { #if FMT_USE_FILE_DESCRIPTORS +using fmt::BufferedFile; +using fmt::ErrorCode; +using fmt::File; + // Checks if the file is open by reading one character from it. bool IsOpen(int fd) { char buffer; diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 41a80a28..e11b49db 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -29,7 +29,7 @@ #if FMT_USE_FILE_DESCRIPTORS -#include "posix.cc" +using fmt::File; void OutputRedirect::Flush() { #if EOF != -1 diff --git a/test/gtest-extra.h b/test/gtest-extra.h index 3211c062..c19ed889 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -99,8 +99,8 @@ std::string FormatSystemErrorMessage(int error_code, fmt::StringRef message); class OutputRedirect { private: FILE *file_; - File original_; // Original file passed to redirector. - File read_end_; // Read end of the pipe where the output is redirected. + fmt::File original_; // Original file passed to redirector. + fmt::File read_end_; // Read end of the pipe where the output is redirected. GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect); diff --git a/test/posix-test.cc b/test/posix-test.cc index 5c9ab023..5dcebcd3 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -37,6 +37,10 @@ #include "gtest-extra.h" +using fmt::BufferedFile; +using fmt::ErrorCode; +using fmt::File; + namespace { int open_count; int close_count;