1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - custom Google Test assertions
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2012 - present, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker
8*5c90c05cSAndroid Build Coastguard Worker #include "gtest-extra.h"
9*5c90c05cSAndroid Build Coastguard Worker
10*5c90c05cSAndroid Build Coastguard Worker #if FMT_USE_FCNTL
11*5c90c05cSAndroid Build Coastguard Worker
12*5c90c05cSAndroid Build Coastguard Worker using fmt::file;
13*5c90c05cSAndroid Build Coastguard Worker
output_redirect(FILE * f,bool flush)14*5c90c05cSAndroid Build Coastguard Worker output_redirect::output_redirect(FILE* f, bool flush) : file_(f) {
15*5c90c05cSAndroid Build Coastguard Worker if (flush) this->flush();
16*5c90c05cSAndroid Build Coastguard Worker int fd = FMT_POSIX(fileno(f));
17*5c90c05cSAndroid Build Coastguard Worker // Create a file object referring to the original file.
18*5c90c05cSAndroid Build Coastguard Worker original_ = file::dup(fd);
19*5c90c05cSAndroid Build Coastguard Worker // Create a pipe.
20*5c90c05cSAndroid Build Coastguard Worker auto pipe = fmt::pipe();
21*5c90c05cSAndroid Build Coastguard Worker read_end_ = std::move(pipe.read_end);
22*5c90c05cSAndroid Build Coastguard Worker // Connect the passed FILE object to the write end of the pipe.
23*5c90c05cSAndroid Build Coastguard Worker pipe.write_end.dup2(fd);
24*5c90c05cSAndroid Build Coastguard Worker }
25*5c90c05cSAndroid Build Coastguard Worker
~output_redirect()26*5c90c05cSAndroid Build Coastguard Worker output_redirect::~output_redirect() noexcept {
27*5c90c05cSAndroid Build Coastguard Worker try {
28*5c90c05cSAndroid Build Coastguard Worker restore();
29*5c90c05cSAndroid Build Coastguard Worker } catch (const std::exception& e) {
30*5c90c05cSAndroid Build Coastguard Worker std::fputs(e.what(), stderr);
31*5c90c05cSAndroid Build Coastguard Worker }
32*5c90c05cSAndroid Build Coastguard Worker }
33*5c90c05cSAndroid Build Coastguard Worker
flush()34*5c90c05cSAndroid Build Coastguard Worker void output_redirect::flush() {
35*5c90c05cSAndroid Build Coastguard Worker int result = 0;
36*5c90c05cSAndroid Build Coastguard Worker do {
37*5c90c05cSAndroid Build Coastguard Worker result = fflush(file_);
38*5c90c05cSAndroid Build Coastguard Worker } while (result == EOF && errno == EINTR);
39*5c90c05cSAndroid Build Coastguard Worker if (result != 0) throw fmt::system_error(errno, "cannot flush stream");
40*5c90c05cSAndroid Build Coastguard Worker }
41*5c90c05cSAndroid Build Coastguard Worker
restore()42*5c90c05cSAndroid Build Coastguard Worker void output_redirect::restore() {
43*5c90c05cSAndroid Build Coastguard Worker if (original_.descriptor() == -1) return; // Already restored.
44*5c90c05cSAndroid Build Coastguard Worker flush();
45*5c90c05cSAndroid Build Coastguard Worker // Restore the original file.
46*5c90c05cSAndroid Build Coastguard Worker original_.dup2(FMT_POSIX(fileno(file_)));
47*5c90c05cSAndroid Build Coastguard Worker original_.close();
48*5c90c05cSAndroid Build Coastguard Worker }
49*5c90c05cSAndroid Build Coastguard Worker
restore_and_read()50*5c90c05cSAndroid Build Coastguard Worker std::string output_redirect::restore_and_read() {
51*5c90c05cSAndroid Build Coastguard Worker // Restore output.
52*5c90c05cSAndroid Build Coastguard Worker restore();
53*5c90c05cSAndroid Build Coastguard Worker
54*5c90c05cSAndroid Build Coastguard Worker // Read everything from the pipe.
55*5c90c05cSAndroid Build Coastguard Worker std::string content;
56*5c90c05cSAndroid Build Coastguard Worker if (read_end_.descriptor() == -1) return content; // Already read.
57*5c90c05cSAndroid Build Coastguard Worker enum { BUFFER_SIZE = 4096 };
58*5c90c05cSAndroid Build Coastguard Worker char buffer[BUFFER_SIZE];
59*5c90c05cSAndroid Build Coastguard Worker size_t count = 0;
60*5c90c05cSAndroid Build Coastguard Worker do {
61*5c90c05cSAndroid Build Coastguard Worker count = read_end_.read(buffer, BUFFER_SIZE);
62*5c90c05cSAndroid Build Coastguard Worker content.append(buffer, count);
63*5c90c05cSAndroid Build Coastguard Worker } while (count != 0);
64*5c90c05cSAndroid Build Coastguard Worker read_end_.close();
65*5c90c05cSAndroid Build Coastguard Worker return content;
66*5c90c05cSAndroid Build Coastguard Worker }
67*5c90c05cSAndroid Build Coastguard Worker
read(file & f,size_t count)68*5c90c05cSAndroid Build Coastguard Worker std::string read(file& f, size_t count) {
69*5c90c05cSAndroid Build Coastguard Worker std::string buffer(count, '\0');
70*5c90c05cSAndroid Build Coastguard Worker size_t n = 0, offset = 0;
71*5c90c05cSAndroid Build Coastguard Worker do {
72*5c90c05cSAndroid Build Coastguard Worker n = f.read(&buffer[offset], count - offset);
73*5c90c05cSAndroid Build Coastguard Worker // We can't read more than size_t bytes since count has type size_t.
74*5c90c05cSAndroid Build Coastguard Worker offset += n;
75*5c90c05cSAndroid Build Coastguard Worker } while (offset < count && n != 0);
76*5c90c05cSAndroid Build Coastguard Worker buffer.resize(offset);
77*5c90c05cSAndroid Build Coastguard Worker return buffer;
78*5c90c05cSAndroid Build Coastguard Worker }
79*5c90c05cSAndroid Build Coastguard Worker
80*5c90c05cSAndroid Build Coastguard Worker #endif // FMT_USE_FCNTL
81