mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-09 18:45:18 +00:00
FileDescriptor -> File
This commit is contained in:
parent
98b6e59272
commit
c5c2cd63bc
@ -145,15 +145,15 @@ TEST(ErrorCodeTest, Ctor) {
|
|||||||
EXPECT_EQ(42, ErrorCode(42).get());
|
EXPECT_EQ(42, ErrorCode(42).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, DefaultCtor) {
|
TEST(FileTest, DefaultCtor) {
|
||||||
FileDescriptor fd;
|
File f;
|
||||||
EXPECT_EQ(-1, fd.get());
|
EXPECT_EQ(-1, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, OpenFileInCtor) {
|
TEST(FileTest, OpenFileInCtor) {
|
||||||
FILE *f = 0;
|
FILE *f = 0;
|
||||||
{
|
{
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File fd(".travis.yml", File::RDONLY);
|
||||||
f = fdopen(fd.get(), "r");
|
f = fdopen(fd.get(), "r");
|
||||||
ASSERT_TRUE(f != 0);
|
ASSERT_TRUE(f != 0);
|
||||||
}
|
}
|
||||||
@ -163,29 +163,28 @@ TEST(FileDescriptorTest, OpenFileInCtor) {
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, OpenFileError) {
|
TEST(FileTest, OpenFileError) {
|
||||||
EXPECT_SYSTEM_ERROR(
|
EXPECT_SYSTEM_ERROR(File("nonexistent", File::RDONLY),
|
||||||
FileDescriptor("nonexistent", FileDescriptor::RDONLY), ENOENT,
|
ENOENT, "cannot open file nonexistent");
|
||||||
"cannot open file nonexistent");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveCtor) {
|
TEST(FileTest, MoveCtor) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
int fd_value = fd.get();
|
int fd = f.get();
|
||||||
EXPECT_NE(-1, fd_value);
|
EXPECT_NE(-1, fd);
|
||||||
FileDescriptor fd2(std::move(fd));
|
File f2(std::move(f));
|
||||||
EXPECT_EQ(fd_value, fd2.get());
|
EXPECT_EQ(fd, f2.get());
|
||||||
EXPECT_EQ(-1, fd.get());
|
EXPECT_EQ(-1, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveAssignment) {
|
TEST(FileTest, MoveAssignment) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
int fd_value = fd.get();
|
int fd = f.get();
|
||||||
EXPECT_NE(-1, fd_value);
|
EXPECT_NE(-1, fd);
|
||||||
FileDescriptor fd2;
|
File f2;
|
||||||
fd2 = std::move(fd);
|
f2 = std::move(f);
|
||||||
EXPECT_EQ(fd_value, fd2.get());
|
EXPECT_EQ(fd, f2.get());
|
||||||
EXPECT_EQ(-1, fd.get());
|
EXPECT_EQ(-1, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsClosed(int fd) {
|
bool IsClosed(int fd) {
|
||||||
@ -194,48 +193,48 @@ bool IsClosed(int fd) {
|
|||||||
return result == -1 && errno == EBADF;
|
return result == -1 && errno == EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveAssignmentClosesFile) {
|
TEST(FileTest, MoveAssignmentClosesFile) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
FileDescriptor fd2("CMakeLists.txt", FileDescriptor::RDONLY);
|
File f2("CMakeLists.txt", File::RDONLY);
|
||||||
int old_fd = fd2.get();
|
int old_fd = f2.get();
|
||||||
fd2 = std::move(fd);
|
f2 = std::move(f);
|
||||||
EXPECT_TRUE(IsClosed(old_fd));
|
EXPECT_TRUE(IsClosed(old_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor OpenFile(int &fd_value) {
|
File OpenFile(int &fd) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
fd_value = fd.get();
|
fd = f.get();
|
||||||
return std::move(fd);
|
return std::move(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveFromTemporaryInCtor) {
|
TEST(FileTest, MoveFromTemporaryInCtor) {
|
||||||
int fd_value = 0xdeadbeef;
|
int fd = 0xdeadbeef;
|
||||||
FileDescriptor fd(OpenFile(fd_value));
|
File f(OpenFile(fd));
|
||||||
EXPECT_EQ(fd_value, fd.get());
|
EXPECT_EQ(fd, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveFromTemporaryInAssignment) {
|
TEST(FileTest, MoveFromTemporaryInAssignment) {
|
||||||
int fd_value = 0xdeadbeef;
|
int fd = 0xdeadbeef;
|
||||||
FileDescriptor fd;
|
File f;
|
||||||
fd = OpenFile(fd_value);
|
f = OpenFile(fd);
|
||||||
EXPECT_EQ(fd_value, fd.get());
|
EXPECT_EQ(fd, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, MoveFromTemporaryInAssignmentClosesFile) {
|
TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
|
||||||
int fd_value = 0xdeadbeef;
|
int fd = 0xdeadbeef;
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
int old_fd = fd.get();
|
int old_fd = f.get();
|
||||||
fd = OpenFile(fd_value);
|
f = OpenFile(fd);
|
||||||
EXPECT_TRUE(IsClosed(old_fd));
|
EXPECT_TRUE(IsClosed(old_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, CloseFileInDtor) {
|
TEST(FileTest, CloseFileInDtor) {
|
||||||
int fd_value = 0;
|
int fd = 0;
|
||||||
{
|
{
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
fd_value = fd.get();
|
fd = f.get();
|
||||||
}
|
}
|
||||||
FILE *f = fdopen(fd_value, "r");
|
FILE *f = fdopen(fd, "r");
|
||||||
int error_code = errno;
|
int error_code = errno;
|
||||||
if (f)
|
if (f)
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -243,89 +242,88 @@ TEST(FileDescriptorTest, CloseFileInDtor) {
|
|||||||
EXPECT_EQ(EBADF, error_code);
|
EXPECT_EQ(EBADF, error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, CloseError) {
|
TEST(FileTest, CloseError) {
|
||||||
FileDescriptor *fd =
|
File *fd = new File(".travis.yml", File::RDONLY);
|
||||||
new FileDescriptor(".travis.yml", FileDescriptor::RDONLY);
|
|
||||||
EXPECT_STDERR(close(fd->get()); delete fd,
|
EXPECT_STDERR(close(fd->get()); delete fd,
|
||||||
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ReadLine(FileDescriptor &fd) {
|
std::string ReadLine(File &f) {
|
||||||
enum { BUFFER_SIZE = 100 };
|
enum { BUFFER_SIZE = 100 };
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
std::streamsize result = fd.read(buffer, BUFFER_SIZE);
|
std::streamsize result = f.read(buffer, BUFFER_SIZE);
|
||||||
buffer[std::min<std::streamsize>(BUFFER_SIZE - 1, result)] = '\0';
|
buffer[std::min<std::streamsize>(BUFFER_SIZE - 1, result)] = '\0';
|
||||||
if (char *end = strchr(buffer, '\n'))
|
if (char *end = strchr(buffer, '\n'))
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Read) {
|
TEST(FileTest, Read) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
EXPECT_EQ("language: cpp", ReadLine(fd));
|
EXPECT_EQ("language: cpp", ReadLine(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, ReadError) {
|
TEST(FileTest, ReadError) {
|
||||||
FileDescriptor fd;
|
File f;
|
||||||
char buf;
|
char buf;
|
||||||
EXPECT_SYSTEM_ERROR(fd.read(&buf, 1), EBADF, "cannot read from file");
|
EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Dup) {
|
TEST(FileTest, Dup) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
FileDescriptor dup = FileDescriptor::dup(fd.get());
|
File dup = File::dup(f.get());
|
||||||
EXPECT_NE(fd.get(), dup.get());
|
EXPECT_NE(f.get(), dup.get());
|
||||||
EXPECT_EQ("language: cpp", ReadLine(dup));
|
EXPECT_EQ("language: cpp", ReadLine(dup));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, DupError) {
|
TEST(FileTest, DupError) {
|
||||||
EXPECT_SYSTEM_ERROR(FileDescriptor::dup(-1),
|
EXPECT_SYSTEM_ERROR(File::dup(-1),
|
||||||
EBADF, "cannot duplicate file descriptor -1");
|
EBADF, "cannot duplicate file descriptor -1");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Dup2) {
|
TEST(FileTest, Dup2) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
FileDescriptor dup("CMakeLists.txt", FileDescriptor::RDONLY);
|
File dup("CMakeLists.txt", File::RDONLY);
|
||||||
fd.dup2(dup.get());
|
f.dup2(dup.get());
|
||||||
EXPECT_NE(fd.get(), dup.get());
|
EXPECT_NE(f.get(), dup.get());
|
||||||
EXPECT_EQ("language: cpp", ReadLine(dup));
|
EXPECT_EQ("language: cpp", ReadLine(dup));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Dup2Error) {
|
TEST(FileTest, Dup2Error) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
EXPECT_SYSTEM_ERROR(fd.dup2(-1), EBADF,
|
EXPECT_SYSTEM_ERROR(f.dup2(-1), EBADF,
|
||||||
fmt::Format("cannot duplicate file descriptor {} to -1") << fd.get());
|
fmt::Format("cannot duplicate file descriptor {} to -1") << f.get());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Dup2NoExcept) {
|
TEST(FileTest, Dup2NoExcept) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
FileDescriptor dup("CMakeLists.txt", FileDescriptor::RDONLY);
|
File dup("CMakeLists.txt", File::RDONLY);
|
||||||
ErrorCode ec;
|
ErrorCode ec;
|
||||||
fd.dup2(dup.get(), ec);
|
f.dup2(dup.get(), ec);
|
||||||
EXPECT_EQ(0, ec.get());
|
EXPECT_EQ(0, ec.get());
|
||||||
EXPECT_NE(fd.get(), dup.get());
|
EXPECT_NE(f.get(), dup.get());
|
||||||
EXPECT_EQ("language: cpp", ReadLine(dup));
|
EXPECT_EQ("language: cpp", ReadLine(dup));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Dup2NoExceptError) {
|
TEST(FileTest, Dup2NoExceptError) {
|
||||||
FileDescriptor fd(".travis.yml", FileDescriptor::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
ErrorCode ec;
|
ErrorCode ec;
|
||||||
fd.dup2(-1, ec);
|
f.dup2(-1, ec);
|
||||||
EXPECT_EQ(EBADF, ec.get());
|
EXPECT_EQ(EBADF, ec.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileDescriptorTest, Pipe) {
|
TEST(FileTest, Pipe) {
|
||||||
FileDescriptor read_fd, write_fd;
|
File read_end, write_end;
|
||||||
FileDescriptor::pipe(read_fd, write_fd);
|
File::pipe(read_end, write_end);
|
||||||
EXPECT_NE(-1, read_fd.get());
|
EXPECT_NE(-1, read_end.get());
|
||||||
EXPECT_NE(-1, write_fd.get());
|
EXPECT_NE(-1, write_end.get());
|
||||||
// TODO: try writing to write_fd and reading from read_fd
|
// TODO: try writing to write_fd and reading from read_fd
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test pipe
|
// TODO: test pipe
|
||||||
|
|
||||||
// TODO: test FileDescriptor::read
|
// TODO: test File::read
|
||||||
|
|
||||||
// TODO: compile both with C++11 & C++98 mode
|
// TODO: compile both with C++11 & C++98 mode
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
result = (expression); \
|
result = (expression); \
|
||||||
} while (result == -1 && errno == EINTR)
|
} while (result == -1 && errno == EINTR)
|
||||||
|
|
||||||
FileDescriptor::FileDescriptor(const char *path, int oflag) {
|
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;
|
||||||
@ -63,7 +63,7 @@ FileDescriptor::FileDescriptor(const char *path, int oflag) {
|
|||||||
fmt::ThrowSystemError(errno, "cannot open file {}") << path;
|
fmt::ThrowSystemError(errno, "cannot open file {}") << path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDescriptor::close() {
|
void File::close() {
|
||||||
if (fd_ == -1)
|
if (fd_ == -1)
|
||||||
return;
|
return;
|
||||||
// Don't need to retry close in case of EINTR.
|
// Don't need to retry close in case of EINTR.
|
||||||
@ -72,7 +72,7 @@ void FileDescriptor::close() {
|
|||||||
fmt::ReportSystemError(errno, "cannot close file");
|
fmt::ReportSystemError(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize FileDescriptor::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, ::read(fd_, buffer, count));
|
FMT_RETRY(result, ::read(fd_, buffer, count));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
@ -80,7 +80,7 @@ std::streamsize FileDescriptor::read(void *buffer, std::size_t count) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize FileDescriptor::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, ::write(fd_, buffer, count));
|
FMT_RETRY(result, ::write(fd_, buffer, count));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
@ -88,15 +88,15 @@ std::streamsize FileDescriptor::write(const void *buffer, std::size_t count) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor FileDescriptor::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(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 FileDescriptor(new_fd);
|
return File(new_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDescriptor::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(dup2(fd_, fd)));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
@ -105,18 +105,18 @@ void FileDescriptor::dup2(int fd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDescriptor::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(dup2(fd_, fd)));
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
ec = ErrorCode(errno);
|
ec = ErrorCode(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileDescriptor::pipe(FileDescriptor &read_fd, FileDescriptor &write_fd) {
|
void File::pipe(File &read_end, File &write_end) {
|
||||||
// Close the descriptors first to make sure that assignments don't throw
|
// Close the descriptors first to make sure that assignments don't throw
|
||||||
// and there are no leaks.
|
// and there are no leaks.
|
||||||
read_fd.close();
|
read_end.close();
|
||||||
write_fd.close();
|
write_end.close();
|
||||||
int fds[2] = {};
|
int fds[2] = {};
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||||
@ -130,25 +130,25 @@ void FileDescriptor::pipe(FileDescriptor &read_fd, FileDescriptor &write_fd) {
|
|||||||
fmt::ThrowSystemError(errno, "cannot create pipe");
|
fmt::ThrowSystemError(errno, "cannot create pipe");
|
||||||
// The following assignments don't throw because read_fd and write_fd
|
// The following assignments don't throw because read_fd and write_fd
|
||||||
// are closed.
|
// are closed.
|
||||||
read_fd = FileDescriptor(fds[0]);
|
read_end = File(fds[0]);
|
||||||
write_fd = FileDescriptor(fds[1]);
|
write_end = File(fds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirector::OutputRedirector(FILE *file) : file_(file) {
|
OutputRedirector::OutputRedirector(FILE *file) : file_(file) {
|
||||||
if (std::fflush(file) != 0)
|
if (std::fflush(file) != 0)
|
||||||
fmt::ThrowSystemError(errno, "cannot flush stream");
|
fmt::ThrowSystemError(errno, "cannot flush stream");
|
||||||
int fd = fileno(file);
|
int fd = fileno(file);
|
||||||
saved_fd_ = FileDescriptor::dup(fd);
|
saved_ = File::dup(fd);
|
||||||
FileDescriptor write_fd;
|
File write_end;
|
||||||
FileDescriptor::pipe(read_fd_, write_fd);
|
File::pipe(read_end_, write_end);
|
||||||
write_fd.dup2(fd);
|
write_end.dup2(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirector::~OutputRedirector() {
|
OutputRedirector::~OutputRedirector() {
|
||||||
if (std::fflush(file_) != 0)
|
if (std::fflush(file_) != 0)
|
||||||
fmt::ReportSystemError(errno, "cannot flush stream");
|
fmt::ReportSystemError(errno, "cannot flush stream");
|
||||||
ErrorCode ec;
|
ErrorCode ec;
|
||||||
saved_fd_.dup2(fileno(file_), ec);
|
saved_.dup2(fileno(file_), ec);
|
||||||
if (ec.get())
|
if (ec.get())
|
||||||
fmt::ReportSystemError(errno, "cannot restore output");
|
fmt::ReportSystemError(errno, "cannot restore output");
|
||||||
}
|
}
|
||||||
@ -157,7 +157,7 @@ std::string OutputRedirector::Read() {
|
|||||||
// Restore output.
|
// Restore output.
|
||||||
if (std::fflush(file_) != 0)
|
if (std::fflush(file_) != 0)
|
||||||
fmt::ThrowSystemError(errno, "cannot flush stream");
|
fmt::ThrowSystemError(errno, "cannot flush stream");
|
||||||
saved_fd_.dup2(fileno(file_));
|
saved_.dup2(fileno(file_));
|
||||||
|
|
||||||
// Read everything from the pipe.
|
// Read everything from the pipe.
|
||||||
std::string content;
|
std::string content;
|
||||||
@ -165,7 +165,7 @@ std::string OutputRedirector::Read() {
|
|||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
std::streamsize count = 0;
|
std::streamsize count = 0;
|
||||||
do {
|
do {
|
||||||
count = read_fd_.read(buffer, BUFFER_SIZE);
|
count = read_end_.read(buffer, BUFFER_SIZE);
|
||||||
content.append(buffer, count);
|
content.append(buffer, count);
|
||||||
} while (count != 0);
|
} while (count != 0);
|
||||||
return content;
|
return content;
|
||||||
|
@ -103,16 +103,16 @@ class ErrorCode {
|
|||||||
int get() const FMT_NOEXCEPT(true) { return value_; }
|
int get() const FMT_NOEXCEPT(true) { return value_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A RAII class for file descriptors.
|
// A file.
|
||||||
class FileDescriptor {
|
class File {
|
||||||
private:
|
private:
|
||||||
int fd_;
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
// Closes the file if its descriptor is not -1.
|
// Closes the file if its descriptor is not -1.
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
// Constructs a FileDescriptor object with a given descriptor.
|
// Constructs a File object with a given descriptor.
|
||||||
explicit FileDescriptor(int fd) : fd_(fd) {}
|
explicit File(int fd) : fd_(fd) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Possible values for the oflag argument to the constructor.
|
// Possible values for the oflag argument to the constructor.
|
||||||
@ -122,13 +122,12 @@ class FileDescriptor {
|
|||||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a FileDescriptor object with a descriptor of -1 which
|
// Constructs a File object which doesn't represent any file.
|
||||||
// is ignored by the destructor.
|
File() FMT_NOEXCEPT(true) : fd_(-1) {}
|
||||||
FileDescriptor() FMT_NOEXCEPT(true) : fd_(-1) {}
|
|
||||||
|
|
||||||
// Opens a file and constructs a FileDescriptor object with the descriptor
|
// Opens a file and constructs a File object representing this file.
|
||||||
// of the opened file. Throws fmt::SystemError on error.
|
// Throws fmt::SystemError on error.
|
||||||
FileDescriptor(const char *path, int oflag);
|
File(const char *path, int oflag);
|
||||||
|
|
||||||
#if !FMT_USE_RVALUE_REFERENCES
|
#if !FMT_USE_RVALUE_REFERENCES
|
||||||
// Emulate a move constructor and a move assignment operator if rvalue
|
// Emulate a move constructor and a move assignment operator if rvalue
|
||||||
@ -143,22 +142,22 @@ class FileDescriptor {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// A "move" constructor for moving from a temporary.
|
// A "move" constructor for moving from a temporary.
|
||||||
FileDescriptor(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.
|
// A "move" constructor for for moving from an lvalue.
|
||||||
FileDescriptor(FileDescriptor &other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
File(File &other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A "move" assignment operator for moving from a temporary.
|
// A "move" assignment operator for moving from a temporary.
|
||||||
FileDescriptor &operator=(Proxy p) {
|
File &operator=(Proxy p) {
|
||||||
close();
|
close();
|
||||||
fd_ = p.fd;
|
fd_ = p.fd;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A "move" assignment operator for moving from an lvalue.
|
// A "move" assignment operator for moving from an lvalue.
|
||||||
FileDescriptor &operator=(FileDescriptor &other) {
|
File &operator=(File &other) {
|
||||||
close();
|
close();
|
||||||
fd_ = other.fd_;
|
fd_ = other.fd_;
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
@ -166,7 +165,7 @@ class FileDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a proxy object for moving from a temporary:
|
// Returns a proxy object for moving from a temporary:
|
||||||
// FileDescriptor fd = FileDescriptor(...);
|
// File file = File(...);
|
||||||
operator Proxy() FMT_NOEXCEPT(true) {
|
operator Proxy() FMT_NOEXCEPT(true) {
|
||||||
Proxy p = {fd_};
|
Proxy p = {fd_};
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
@ -174,37 +173,36 @@ class FileDescriptor {
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
private:
|
private:
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(FileDescriptor);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(File);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileDescriptor(FileDescriptor &&other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
File(File &&other) FMT_NOEXCEPT(true) : fd_(other.fd_) {
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor& operator=(FileDescriptor &&other) FMT_NOEXCEPT(true) {
|
File& operator=(File &&other) FMT_NOEXCEPT(true) {
|
||||||
fd_ = other.fd_;
|
fd_ = other.fd_;
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Closes the file if its descriptor is not -1 and destroys the object.
|
// Destroys the object closing the file it represents if any.
|
||||||
~FileDescriptor() { close(); }
|
~File() { close(); }
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
|
// TODO: rename
|
||||||
int get() const FMT_NOEXCEPT(true) { return fd_; }
|
int get() const FMT_NOEXCEPT(true) { return fd_; }
|
||||||
|
|
||||||
// Attempts to read count bytes from the file associated with this file
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
// descriptor into the specified buffer.
|
|
||||||
std::streamsize read(void *buffer, std::size_t count);
|
std::streamsize read(void *buffer, std::size_t count);
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
// associated with this file descriptor.
|
|
||||||
std::streamsize write(const void *buffer, std::size_t count);
|
std::streamsize write(const void *buffer, std::size_t count);
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate. Throws fmt::SystemError on error.
|
// the duplicate as a file object. Throws fmt::SystemError on error.
|
||||||
static FileDescriptor dup(int fd);
|
static File dup(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary. Throws fmt::SystemError on error.
|
// necessary. Throws fmt::SystemError on error.
|
||||||
@ -214,15 +212,15 @@ class FileDescriptor {
|
|||||||
// necessary.
|
// necessary.
|
||||||
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true);
|
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true);
|
||||||
|
|
||||||
// Creates a pipe setting up read and write file descriptors for reading
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respecively. Throws fmt::SystemError on error.
|
// and writing respectively. Throws fmt::SystemError on error.
|
||||||
static void pipe(FileDescriptor &read_fd, FileDescriptor &write_fd);
|
static void pipe(File &read_end, File &write_end);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !FMT_USE_RVALUE_REFERENCES
|
#if !FMT_USE_RVALUE_REFERENCES
|
||||||
namespace std {
|
namespace std {
|
||||||
// For compatibility with C++98.
|
// For compatibility with C++98.
|
||||||
inline FileDescriptor &move(FileDescriptor &fd) { return fd; }
|
inline File &move(File &f) { return f; }
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -230,9 +228,8 @@ inline FileDescriptor &move(FileDescriptor &fd) { return fd; }
|
|||||||
class OutputRedirector {
|
class OutputRedirector {
|
||||||
private:
|
private:
|
||||||
FILE *file_;
|
FILE *file_;
|
||||||
FileDescriptor saved_fd_; // Saved file descriptor created with dup.
|
File saved_; // Saved file created with dup.
|
||||||
FileDescriptor read_fd_; // Read end of the pipe where the output is
|
File read_end_; // Read end of the pipe where the output is redirected.
|
||||||
// redirected.
|
|
||||||
|
|
||||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirector);
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirector);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user