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