cprover
cout_message.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "cout_message.h"
10 
11 #include <fstream>
12 #include <iostream>
13 
14 #ifdef _WIN32
15 #include <util/pragma_push.def>
16 #ifdef _MSC_VER
17 #pragma warning(disable:4668)
18  // using #if/#elif on undefined macro
19 #endif
20 #include <windows.h>
21 #include <fcntl.h>
22 #include <io.h>
23 #include <cstdio>
24 #include <util/pragma_pop.def>
25 #else
26 #include <unistd.h>
27 #endif
28 
29 #include "unicode.h"
30 
33 {
34 }
35 
38 {
39 }
40 
42  : always_flush(_always_flush), is_a_tty(false), use_SGR(false)
43 {
44 #ifdef _WIN32
45  HANDLE out_handle=GetStdHandle(STD_OUTPUT_HANDLE);
46 
47  DWORD consoleMode;
48  if(GetConsoleMode(out_handle, &consoleMode))
49  {
50  is_a_tty = true;
51 
52 #ifdef ENABLE_VIRTUAL_TERMINAL_PROCESSING
53  consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
54  if(SetConsoleMode(out_handle, consoleMode))
55  use_SGR = true;
56 #endif
57  }
58 #else
59  is_a_tty = isatty(STDOUT_FILENO);
60  use_SGR = is_a_tty;
61 #endif
62 }
63 
67 std::string console_message_handlert::command(unsigned c) const
68 {
69  if(!use_SGR)
70  return std::string();
71 
72  return "\x1b[" + std::to_string(c) + 'm';
73 }
74 
76  unsigned level,
77  const std::string &message)
78 {
79  message_handlert::print(level, message);
80 
81  if(verbosity<level)
82  return;
83 
84  #ifdef _WIN32
85  HANDLE out_handle=
86  GetStdHandle((level>1)?STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
87 
88  // We use UTF16 when we write to the console,
89  // but we write UTF8 otherwise.
90 
91  DWORD consoleMode;
92  if(GetConsoleMode(out_handle, &consoleMode))
93  {
94  // writing to the console
95  std::wstring wide_message=widen(message);
96 
97  DWORD number_written;
98 
99  WriteConsoleW(
100  out_handle, wide_message.c_str(),
101  (DWORD)wide_message.size(), &number_written, NULL);
102 
103  WriteConsoleW(out_handle, L"\r\n", 2, &number_written, NULL);
104  }
105  else
106  {
107  // writing to a file
108 
109  if(level>=4)
110  {
111  std::cout << message << '\n';
112  }
113  else
114  std::cerr << message << '\n';
115  }
116  #else
117  // Messages level 3 or lower go to cerr, messages level 4 or
118  // above go to cout.
119 
120  if(level>=4)
121  {
122  std::cout << message << '\n';
123  }
124  else
125  std::cerr << message << '\n';
126  #endif
127 }
128 
130 {
131  // We flush after messages of level 6 or lower.
132  // We don't for messages of level 7 or higher to improve performance,
133  // in particular when writing to NFS.
134  if(level>=4)
135  {
136  if(level <= 6 || always_flush)
137  std::cout << std::flush;
138  }
139  else
140  std::cerr << std::flush;
141 }
142 
144  unsigned level,
145  const std::string &message,
146  const source_locationt &location)
147 {
148  message_handlert::print(level, message);
149 
150  if(verbosity >= level)
151  {
152  // gcc appears to send everything to cerr
153  auto &out = std::cerr;
154 
155  const irep_idt file = location.get_file();
156  const irep_idt line = location.get_line();
157  const irep_idt column = location.get_column();
158  const irep_idt function = location.get_function();
159 
160  if(!function.empty())
161  {
162  if(!file.empty())
163  out << string(messaget::bold) << file << ':' << string(messaget::reset)
164  << ' ';
165  out << "In function " << string(messaget::bold) << '\'' << function
166  << '\'' << string(messaget::reset) << ":\n";
167  }
168 
169  if(!line.empty())
170  {
171  out << string(messaget::bold);
172 
173  if(!file.empty())
174  out << file << ':';
175 
176  out << line << ':';
177 
178  if(column.empty())
179  out << "1: ";
180  else
181  out << column << ": ";
182 
183  if(level == messaget::M_ERROR)
184  out << string(messaget::red) << "error: ";
185  else if(level == messaget::M_WARNING)
186  out << string(messaget::bright_magenta) << "warning: ";
187 
188  out << string(messaget::reset);
189  }
190 
191  out << message << '\n';
192 
193  const auto file_name = location.full_path();
194  if(file_name.has_value() && !line.empty())
195  {
196 #ifdef _WIN32
197  std::ifstream in(widen(file_name.value()));
198 #else
199  std::ifstream in(file_name.value());
200 #endif
201  if(in)
202  {
203  const auto line_number = std::stoull(id2string(line));
204  std::string source_line;
205  for(std::size_t l = 0; l < line_number; l++)
206  std::getline(in, source_line);
207 
208  if(in)
209  out << ' ' << source_line << '\n'; // gcc adds a space, clang doesn't
210  }
211  }
212 
213  out << std::flush;
214  }
215 }
216 
218  unsigned level,
219  const std::string &message)
220 {
221  message_handlert::print(level, message);
222 
223  // gcc appears to send everything to cerr
224  if(verbosity>=level)
225  std::cerr << message << '\n' << std::flush;
226 }
static const commandt bright_magenta
render text with bright magenta foreground color
Definition: message.h:363
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
static const commandt bold
render text with bold font
Definition: message.h:369
std::wstring widen(const char *s)
Definition: unicode.cpp:52
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
const irep_idt & get_function() const
STL namespace.
unsigned verbosity
Definition: message.h:67
static const commandt reset
return to default formatting, as defined by the terminal
Definition: message.h:330
const irep_idt & get_column() const
void print(unsigned, const xmlt &) override
Definition: cout_message.h:68
bool use_SGR
true if we use ECMA-48 SGR to render colors
Definition: cout_message.h:62
bool is_a_tty
true if we are outputting to a proper console
Definition: cout_message.h:59
const irep_idt & get_line() const
virtual void flush(unsigned level) override
static const commandt red
render text with red foreground color
Definition: message.h:333
std::string command(unsigned c) const override
Create an ECMA-48 SGR (Select Graphic Rendition) command with given code.
dstringt has one field, an unsigned integer no which is an index into a static table of strings...
Definition: dstring.h:35
const irep_idt & get_file() const
void print(unsigned, const xmlt &) override
Definition: cout_message.h:32
optionalt< std::string > full_path() const
Get a path to the file, including working directory.
std::string string(const messaget::commandt &c) const
feed a command into a string
Definition: cout_message.h:88
bool empty() const
Definition: dstring.h:75
virtual void print(unsigned level, const std::string &message)=0
Definition: message.cpp:58
Definition: kdev_t.h:19