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