• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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