mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-25 06:21:00 +00:00
Use stdio.h instead of cstdio for fdopen. Wrap all used POSIX functions for testing.
This commit is contained in:
parent
d758dbb33a
commit
fb17316d77
@ -65,8 +65,8 @@ class SuppressAssert {
|
|||||||
|
|
||||||
// Fix "secure" warning about using fopen without defining
|
// Fix "secure" warning about using fopen without defining
|
||||||
// _CRT_SECURE_NO_WARNINGS.
|
// _CRT_SECURE_NO_WARNINGS.
|
||||||
std::FILE *OpenFile(const char *filename, const char *mode) {
|
FILE *OpenFile(const char *filename, const char *mode) {
|
||||||
std::FILE *f = 0;
|
FILE *f = 0;
|
||||||
errno = fopen_s(&f, filename, mode);
|
errno = fopen_s(&f, filename, mode);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,6 @@
|
|||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#ifdef FMT_INCLUDE_POSIX_TEST
|
|
||||||
# include "posix-test.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Retries the expression while it evaluates to -1 and error equals to EINTR.
|
// Retries the expression while it evaluates to -1 and error equals to EINTR.
|
||||||
#define FMT_RETRY(result, expression) \
|
#define FMT_RETRY(result, expression) \
|
||||||
do { \
|
do { \
|
||||||
@ -60,6 +56,7 @@ namespace {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// On Windows the count argument to read and write is unsigned, so convert
|
// On Windows the count argument to read and write is unsigned, so convert
|
||||||
// it from size_t preventing integer overflow.
|
// it from size_t preventing integer overflow.
|
||||||
|
// TODO: test
|
||||||
inline unsigned ConvertRWCount(std::size_t count) {
|
inline unsigned ConvertRWCount(std::size_t count) {
|
||||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||||
}
|
}
|
||||||
@ -83,7 +80,7 @@ void BufferedFile::close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int BufferedFile::fileno() const {
|
int BufferedFile::fileno() const {
|
||||||
int fd = ::FMT_POSIX(fileno(file_));
|
int fd = FMT_POSIX_CALL(fileno(file_));
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot get file descriptor");
|
fmt::ThrowSystemError(errno, "cannot get file descriptor");
|
||||||
return fd;
|
return fd;
|
||||||
@ -93,9 +90,9 @@ File::File(const char *path, int oflag) {
|
|||||||
int mode = S_IRUSR | S_IWUSR;
|
int mode = S_IRUSR | S_IWUSR;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
_sopen_s(&fd_, path, oflag, _SH_DENYNO, mode);
|
FMT_POSIX_CALL(sopen_s(&fd_, path, oflag, _SH_DENYNO, mode));
|
||||||
#else
|
#else
|
||||||
FMT_RETRY(fd_, open(path, oflag, mode));
|
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path, oflag, mode)));
|
||||||
#endif
|
#endif
|
||||||
if (fd_ == -1)
|
if (fd_ == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot open file {}") << path;
|
fmt::ThrowSystemError(errno, "cannot open file {}") << path;
|
||||||
@ -104,7 +101,7 @@ File::File(const char *path, int oflag) {
|
|||||||
File::~File() FMT_NOEXCEPT(true) {
|
File::~File() FMT_NOEXCEPT(true) {
|
||||||
// Don't retry close in case of EINTR!
|
// Don't retry close in case of EINTR!
|
||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
if (fd_ != -1 && ::FMT_POSIX(close(fd_)) != 0)
|
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||||
fmt::ReportSystemError(errno, "cannot close file");
|
fmt::ReportSystemError(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +110,7 @@ void File::close() {
|
|||||||
return;
|
return;
|
||||||
// Don't retry close in case of EINTR!
|
// Don't retry close in case of EINTR!
|
||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
int result = ::FMT_POSIX(close(fd_));
|
int result = FMT_POSIX_CALL(close(fd_));
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
fmt::ThrowSystemError(errno, "cannot close file");
|
fmt::ThrowSystemError(errno, "cannot close file");
|
||||||
@ -121,7 +118,7 @@ void File::close() {
|
|||||||
|
|
||||||
std::streamsize File::read(void *buffer, std::size_t count) {
|
std::streamsize File::read(void *buffer, std::size_t count) {
|
||||||
std::streamsize result = 0;
|
std::streamsize result = 0;
|
||||||
FMT_RETRY(result, ::FMT_POSIX(read(fd_, buffer, ConvertRWCount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, ConvertRWCount(count))));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot read from file");
|
fmt::ThrowSystemError(errno, "cannot read from file");
|
||||||
return result;
|
return result;
|
||||||
@ -129,7 +126,7 @@ std::streamsize File::read(void *buffer, std::size_t count) {
|
|||||||
|
|
||||||
std::streamsize File::write(const void *buffer, std::size_t count) {
|
std::streamsize File::write(const void *buffer, std::size_t count) {
|
||||||
std::streamsize result = 0;
|
std::streamsize result = 0;
|
||||||
FMT_RETRY(result, ::FMT_POSIX(write(fd_, buffer, ConvertRWCount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, ConvertRWCount(count))));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot write to file");
|
fmt::ThrowSystemError(errno, "cannot write to file");
|
||||||
return result;
|
return result;
|
||||||
@ -137,7 +134,7 @@ std::streamsize File::write(const void *buffer, std::size_t count) {
|
|||||||
|
|
||||||
File File::dup(int fd) {
|
File File::dup(int fd) {
|
||||||
int new_fd = 0;
|
int new_fd = 0;
|
||||||
FMT_RETRY(new_fd, ::FMT_POSIX(dup(fd)));
|
FMT_RETRY(new_fd, FMT_POSIX_CALL(dup(fd)));
|
||||||
if (new_fd == -1)
|
if (new_fd == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot duplicate file descriptor {}") << fd;
|
fmt::ThrowSystemError(errno, "cannot duplicate file descriptor {}") << fd;
|
||||||
return File(new_fd);
|
return File(new_fd);
|
||||||
@ -145,7 +142,7 @@ File File::dup(int fd) {
|
|||||||
|
|
||||||
void File::dup2(int fd) {
|
void File::dup2(int fd) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, ::FMT_POSIX(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
fmt::ThrowSystemError(errno,
|
fmt::ThrowSystemError(errno,
|
||||||
"cannot duplicate file descriptor {} to {}") << fd_ << fd;
|
"cannot duplicate file descriptor {} to {}") << fd_ << fd;
|
||||||
@ -154,7 +151,7 @@ void File::dup2(int fd) {
|
|||||||
|
|
||||||
void File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) {
|
void File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, ::FMT_POSIX(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
ec = ErrorCode(errno);
|
ec = ErrorCode(errno);
|
||||||
}
|
}
|
||||||
@ -182,7 +179,7 @@ void File::pipe(File &read_end, File &write_end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BufferedFile File::fdopen(const char *mode) {
|
BufferedFile File::fdopen(const char *mode) {
|
||||||
BufferedFile f(::FMT_POSIX(fdopen(fd_, mode)));
|
BufferedFile f(FMT_POSIX_CALL(fdopen(fd_, mode)));
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@ -206,7 +203,7 @@ void OutputRedirect::Restore() {
|
|||||||
original_.close();
|
original_.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirect::OutputRedirect(std::FILE *file) : file_(file) {
|
OutputRedirect::OutputRedirect(FILE *file) : file_(file) {
|
||||||
Flush();
|
Flush();
|
||||||
int fd = FMT_POSIX(fileno(file));
|
int fd = FMT_POSIX(fileno(file));
|
||||||
// Create a File object referring to the original file.
|
// Create a File object referring to the original file.
|
||||||
|
@ -29,10 +29,11 @@
|
|||||||
#define FMT_GTEST_EXTRA_H
|
#define FMT_GTEST_EXTRA_H
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
@ -41,6 +42,10 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#ifdef FMT_INCLUDE_POSIX_TEST
|
||||||
|
# include "posix-test.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
|
||||||
@ -93,11 +98,22 @@ std::string FormatSystemErrorMessage(int error_code, fmt::StringRef message);
|
|||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifndef FMT_POSIX
|
||||||
|
# ifdef _WIN32
|
||||||
// Fix warnings about deprecated symbols.
|
// Fix warnings about deprecated symbols.
|
||||||
# define FMT_POSIX(name) _##name
|
# define FMT_POSIX(name) _##name
|
||||||
#else
|
# else
|
||||||
# define FMT_POSIX(name) name
|
# define FMT_POSIX(name) name
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FMT_POSIX_CALL
|
||||||
|
# ifdef _WIN32
|
||||||
|
// Fix warnings about deprecated symbols.
|
||||||
|
# define FMT_POSIX_CALL(name) ::_##name
|
||||||
|
# else
|
||||||
|
# define FMT_POSIX_CALL(name) ::name
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// An error code.
|
// An error code.
|
||||||
@ -114,11 +130,11 @@ class ErrorCode {
|
|||||||
// A buffered file.
|
// A buffered file.
|
||||||
class BufferedFile {
|
class BufferedFile {
|
||||||
private:
|
private:
|
||||||
std::FILE *file_;
|
FILE *file_;
|
||||||
|
|
||||||
friend class File;
|
friend class File;
|
||||||
|
|
||||||
explicit BufferedFile(std::FILE *f) : file_(f) {}
|
explicit BufferedFile(FILE *f) : file_(f) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructs a BufferedFile object which doesn't represent any file.
|
// Constructs a BufferedFile object which doesn't represent any file.
|
||||||
@ -135,7 +151,7 @@ class BufferedFile {
|
|||||||
// A proxy object to emulate a move constructor.
|
// A proxy object to emulate a move constructor.
|
||||||
// It is private to make it impossible call operator Proxy directly.
|
// It is private to make it impossible call operator Proxy directly.
|
||||||
struct Proxy {
|
struct Proxy {
|
||||||
std::FILE *file;
|
FILE *file;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -190,7 +206,7 @@ class BufferedFile {
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
std::FILE *get() const { return file_; }
|
FILE *get() const { return file_; }
|
||||||
|
|
||||||
int fileno() const;
|
int fileno() const;
|
||||||
};
|
};
|
||||||
@ -329,7 +345,7 @@ inline File &move(File &f) { return f; }
|
|||||||
// The output it can handle is limited by the pipe capacity.
|
// The output it can handle is limited by the pipe capacity.
|
||||||
class OutputRedirect {
|
class OutputRedirect {
|
||||||
private:
|
private:
|
||||||
std::FILE *file_;
|
FILE *file_;
|
||||||
File original_; // Original file passed to redirector.
|
File original_; // Original file passed to redirector.
|
||||||
File read_end_; // Read end of the pipe where the output is redirected.
|
File read_end_; // Read end of the pipe where the output is redirected.
|
||||||
|
|
||||||
@ -339,7 +355,7 @@ class OutputRedirect {
|
|||||||
void Restore();
|
void Restore();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OutputRedirect(std::FILE *file);
|
explicit OutputRedirect(FILE *file);
|
||||||
~OutputRedirect() FMT_NOEXCEPT(true);
|
~OutputRedirect() FMT_NOEXCEPT(true);
|
||||||
|
|
||||||
// Restores the original file, reads output from the pipe into a string
|
// Restores the original file, reads output from the pipe into a string
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
#include "posix-test.h"
|
#include "posix-test.h"
|
||||||
|
|
||||||
#undef open
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
@ -36,29 +34,84 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int open_count;
|
int open_count;
|
||||||
|
int close_count;
|
||||||
|
int dup_count;
|
||||||
|
int dup2_count;
|
||||||
|
int fdopen_count;
|
||||||
|
int fileno_count;
|
||||||
|
int read_count;
|
||||||
|
int write_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EMULATE_EINTR(func, error_result) \
|
||||||
|
if (func##_count != 0) { \
|
||||||
|
if (func##_count++ != 3) { \
|
||||||
|
errno = EINTR; \
|
||||||
|
return error_result; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int test::open(const char *path, int oflag, int mode) {
|
int test::open(const char *path, int oflag, int mode) {
|
||||||
if ((open_count++ % 3) == 2)
|
EMULATE_EINTR(open, -1);
|
||||||
return ::open(path, oflag, mode);
|
return ::open(path, oflag, mode);
|
||||||
errno = EINTR;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
errno_t test::sopen_s(int* pfh, const char *filename, int oflag, int shflag, int pmode) {
|
errno_t test::sopen_s(
|
||||||
|
int* pfh, const char *filename, int oflag, int shflag, int pmode) {
|
||||||
|
EMULATE_EINTR(open, EINTR);
|
||||||
return _sopen_s(pfh, filename, oflag, shflag, pmode);
|
return _sopen_s(pfh, filename, oflag, shflag, pmode);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int test::close(int fildes) {
|
||||||
|
// Close the file first because close shouldn't be retried.
|
||||||
|
int result = ::close(fildes);
|
||||||
|
EMULATE_EINTR(close, -1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test::dup(int fildes) {
|
||||||
|
EMULATE_EINTR(dup, -1);
|
||||||
|
return ::dup(fildes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test::dup2(int fildes, int fildes2) {
|
||||||
|
EMULATE_EINTR(dup2, -1);
|
||||||
|
return ::dup2(fildes, fildes2);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *test::fdopen(int fildes, const char *mode) {
|
||||||
|
EMULATE_EINTR(fdopen, 0);
|
||||||
|
return ::fdopen(fildes, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test::fileno(FILE *stream) {
|
||||||
|
EMULATE_EINTR(fileno, -1);
|
||||||
|
return ::fileno(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
test::ssize_t test::read(int fildes, void *buf, test::size_t nbyte) {
|
||||||
|
EMULATE_EINTR(read, -1);
|
||||||
|
return ::read(fildes, buf, nbyte);
|
||||||
|
}
|
||||||
|
|
||||||
|
test::ssize_t test::write(int fildes, const void *buf, test::size_t nbyte) {
|
||||||
|
EMULATE_EINTR(write, -1);
|
||||||
|
return ::write(fildes, buf, nbyte);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define EXPECT_RETRY(statement, func, message) \
|
# define EXPECT_RETRY(statement, func, message) \
|
||||||
func##_count = 0; \
|
func##_count = 1; \
|
||||||
statement; \
|
statement; \
|
||||||
EXPECT_EQ(3, func##_count);
|
EXPECT_EQ(4, func##_count); \
|
||||||
|
func##_count = 0;
|
||||||
#else
|
#else
|
||||||
# define EXPECT_RETRY(statement, func, message) \
|
# define EXPECT_RETRY(statement, func, message) \
|
||||||
EXPECT_SYSTEM_ERROR(statement, EINTR, message);
|
func##_count = 1; \
|
||||||
|
EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
|
||||||
|
func##_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(FileTest, OpenRetry) {
|
TEST(FileTest, OpenRetry) {
|
||||||
|
@ -29,17 +29,35 @@
|
|||||||
#define FMT_POSIX_TEST_H
|
#define FMT_POSIX_TEST_H
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
// Size type for read and write.
|
||||||
|
typedef size_t size_t;
|
||||||
|
typedef ssize_t ssize_t;
|
||||||
int open(const char *path, int oflag, int mode);
|
int open(const char *path, int oflag, int mode);
|
||||||
#define open test::open
|
|
||||||
#else
|
#else
|
||||||
errno_t sopen_s(int* pfh, const char *filename, int oflag, int shflag, int pmode);
|
typedef unsigned size_t;
|
||||||
#define _sopen_s test::sopen_s
|
typedef int ssize_t;
|
||||||
|
errno_t sopen_s(
|
||||||
|
int* pfh, const char *filename, int oflag, int shflag, int pmode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int close(int fildes);
|
||||||
|
|
||||||
|
int dup(int fildes);
|
||||||
|
int dup2(int fildes, int fildes2);
|
||||||
|
|
||||||
|
FILE *fdopen(int fildes, const char *mode);
|
||||||
|
int fileno(FILE *stream);
|
||||||
|
|
||||||
|
ssize_t read(int fildes, void *buf, size_t nbyte);
|
||||||
|
ssize_t write(int fildes, const void *buf, size_t nbyte);
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
|
#define FMT_POSIX_CALL(call) test::call
|
||||||
|
|
||||||
#endif // FMT_POSIX_TEST_H
|
#endif // FMT_POSIX_TEST_H
|
||||||
|
Loading…
Reference in New Issue
Block a user