1// (C) Copyright Gennadiy Rozental 2001.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6// See http://www.boost.org/libs/test for the library home page.
7//
8// File : $RCSfile$
9//
10// Version : $Revision$
11//
12// Description : contains definition for setcolor iostream manipulator
13// ***************************************************************************
14
15#ifndef BOOST_TEST_UTILS_SETCOLOR_HPP
16#define BOOST_TEST_UTILS_SETCOLOR_HPP
17
18// Boost.Test
19#include <boost/test/detail/config.hpp>
20
21#include <boost/core/ignore_unused.hpp>
22#include <boost/core/snprintf.hpp>
23
24// STL
25#include <iostream>
26#include <cstdio>
27#include <cassert>
28
29#include <boost/test/detail/suppress_warnings.hpp>
30
31#ifdef _WIN32
32 #include <windows.h>
33
34 #if defined(__MINGW32__) && !defined(COMMON_LVB_UNDERSCORE)
35 // mingw badly mimicking windows.h
36 #define COMMON_LVB_UNDERSCORE 0x8000
37 #endif
38#endif
39
40//____________________________________________________________________________//
41
42namespace boost {
43namespace unit_test {
44namespace utils {
45
46// ************************************************************************** //
47// ************** term_attr ************** //
48// ************************************************************************** //
49
50struct term_attr { enum _ {
51 NORMAL = 0,
52 BRIGHT = 1,
53 DIM = 2,
54 UNDERLINE = 4,
55 BLINK = 5,
56 REVERSE = 7,
57 CROSSOUT = 9
58}; };
59
60// ************************************************************************** //
61// ************** term_color ************** //
62// ************************************************************************** //
63
64struct term_color { enum _ {
65 BLACK = 0,
66 RED = 1,
67 GREEN = 2,
68 YELLOW = 3,
69 BLUE = 4,
70 MAGENTA = 5,
71 CYAN = 6,
72 WHITE = 7,
73 ORIGINAL = 9
74}; };
75
76// ************************************************************************** //
77// ************** setcolor ************** //
78// ************************************************************************** //
79
80#ifndef _WIN32
81class setcolor {
82public:
83 typedef int state;
84
85 // Constructor
86 explicit setcolor( bool is_color_output = false,
87 term_attr::_ attr = term_attr::NORMAL,
88 term_color::_ fg = term_color::ORIGINAL,
89 term_color::_ bg = term_color::ORIGINAL,
90 state* /* unused */= NULL)
91 : m_is_color_output(is_color_output)
92 {
93 #ifdef BOOST_MSVC
94 m_command_size = std::sprintf( m_control_command,
95 #else
96 m_command_size = boost::core::snprintf( s: m_control_command, maxlen: sizeof(m_control_command),
97 #endif
98 format: "%c[%c;3%c;4%cm",
99 0x1B,
100 static_cast<char>(attr + '0'),
101 static_cast<char>(fg + '0'),
102 static_cast<char>(bg + '0'));
103 }
104
105 explicit setcolor(bool is_color_output,
106 state* /* unused */)
107 : m_is_color_output(is_color_output)
108 {
109 #ifdef BOOST_MSVC
110 m_command_size = std::sprintf( m_control_command,
111 #else
112 m_command_size = boost::core::snprintf(s: m_control_command, maxlen: sizeof(m_control_command),
113 #endif
114 format: "%c[%c;3%c;4%cm",
115 0x1B,
116 static_cast<char>(term_attr::NORMAL + '0'),
117 static_cast<char>(term_color::ORIGINAL + '0'),
118 static_cast<char>(term_color::ORIGINAL + '0'));
119 }
120
121 friend std::ostream&
122 operator<<( std::ostream& os, setcolor const& sc )
123 {
124 if (sc.m_is_color_output && (&os == &std::cout || &os == &std::cerr)) {
125 return os.write( s: sc.m_control_command, n: sc.m_command_size );
126 }
127 return os;
128 }
129
130private:
131 // Data members
132 bool m_is_color_output;
133 char m_control_command[13];
134 int m_command_size;
135};
136
137#else
138
139class setcolor {
140
141protected:
142 void set_console_color(std::ostream& os, WORD *attributes = NULL) const {
143 if (!m_is_color_output || m_state_saved) {
144 return;
145 }
146 DWORD console_type;
147 if (&os == &std::cout) {
148 console_type = STD_OUTPUT_HANDLE;
149 }
150 else if (&os == &std::cerr) {
151 console_type = STD_ERROR_HANDLE;
152 }
153 else {
154 return;
155 }
156 HANDLE hConsole = GetStdHandle(console_type);
157
158 if(hConsole == INVALID_HANDLE_VALUE || hConsole == NULL )
159 return;
160
161 state console_attributes;
162 if(attributes != NULL || (m_restore_state && m_s)) {
163 if (attributes != NULL) {
164 console_attributes = *attributes;
165 }
166 else {
167 console_attributes = *m_s;
168 *m_s = state();
169 }
170 SetConsoleTextAttribute(hConsole, console_attributes);
171 return;
172 }
173
174 CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
175 GetConsoleScreenBufferInfo(hConsole, &consoleInfo);
176 console_attributes = consoleInfo.wAttributes;
177
178 if (!m_state_saved && m_s) {
179 assert(!m_restore_state);
180 // we can save the state only the first time this object is used
181 // for modifying the console.
182 *m_s = console_attributes;
183 m_state_saved = true;
184 }
185
186 WORD fg_attr = 0;
187 switch(m_fg)
188 {
189 case term_color::WHITE:
190 fg_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
191 break;
192 case term_color::BLACK:
193 fg_attr = 0;
194 break;
195 case term_color::RED:
196 fg_attr = FOREGROUND_RED;
197 break;
198 case term_color::GREEN:
199 fg_attr = FOREGROUND_GREEN;
200 break;
201 case term_color::CYAN:
202 fg_attr = FOREGROUND_GREEN | FOREGROUND_BLUE;
203 break;
204 case term_color::MAGENTA:
205 fg_attr = FOREGROUND_RED | FOREGROUND_BLUE;
206 break;
207 case term_color::BLUE:
208 fg_attr = FOREGROUND_BLUE;
209 break;
210 case term_color::YELLOW:
211 fg_attr = FOREGROUND_RED | FOREGROUND_GREEN;
212 break;
213 case term_color::ORIGINAL:
214 default:
215 fg_attr = console_attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
216 break;
217 }
218
219 WORD bg_attr = 0;
220 switch(m_bg)
221 {
222 case term_color::BLACK:
223 bg_attr = 0;
224 break;
225 case term_color::WHITE:
226 bg_attr = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
227 break;
228 case term_color::RED:
229 bg_attr = BACKGROUND_RED;
230 break;
231 case term_color::GREEN:
232 bg_attr = BACKGROUND_GREEN;
233 break;
234 case term_color::BLUE:
235 bg_attr = BACKGROUND_BLUE;
236 break;
237 case term_color::ORIGINAL:
238 default:
239 bg_attr = console_attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
240 break;
241 }
242
243 WORD text_attr = 0;
244 switch(m_attr)
245 {
246 case term_attr::BRIGHT:
247 text_attr = FOREGROUND_INTENSITY;
248 break;
249 case term_attr::UNDERLINE:
250 text_attr = COMMON_LVB_UNDERSCORE;
251 break;
252 default:
253 break;
254 }
255
256 SetConsoleTextAttribute(hConsole, fg_attr | bg_attr | text_attr);
257 return;
258 }
259
260public:
261 typedef WORD state;
262
263 // Constructor
264 explicit setcolor(
265 bool is_color_output = false,
266 term_attr::_ attr = term_attr::NORMAL,
267 term_color::_ fg = term_color::ORIGINAL,
268 term_color::_ bg = term_color::ORIGINAL,
269 state* s = NULL)
270 : m_is_color_output(is_color_output)
271 , m_attr(attr)
272 , m_fg(fg)
273 , m_bg(bg)
274 , m_s(s)
275 , m_restore_state(false)
276 , m_state_saved(false)
277 {}
278
279 explicit setcolor(
280 bool is_color_output,
281 state* s)
282 : m_is_color_output(is_color_output)
283 , m_attr(term_attr::NORMAL)
284 , m_fg(term_color::ORIGINAL)
285 , m_bg(term_color::ORIGINAL)
286 , m_s(s)
287 , m_restore_state(true)
288 , m_state_saved(false)
289 {}
290
291 friend std::ostream&
292 operator<<( std::ostream& os, setcolor const& sc )
293 {
294 sc.set_console_color(os);
295 return os;
296 }
297
298private:
299 bool m_is_color_output;
300 term_attr::_ m_attr;
301 term_color::_ m_fg;
302 term_color::_ m_bg;
303 state* m_s;
304 // indicates that the instance has been initialized to restore a previously
305 // stored state
306 bool m_restore_state;
307 // indicates the first time we pull and set the console information.
308 mutable bool m_state_saved;
309};
310
311#endif
312// ************************************************************************** //
313// ************** scope_setcolor ************** //
314// ************************************************************************** //
315
316struct scope_setcolor {
317 scope_setcolor()
318 : m_os( 0 )
319 , m_state()
320 , m_is_color_output(false)
321 {}
322
323 explicit scope_setcolor(
324 bool is_color_output,
325 std::ostream& os,
326 term_attr::_ attr = term_attr::NORMAL,
327 term_color::_ fg = term_color::ORIGINAL,
328 term_color::_ bg = term_color::ORIGINAL )
329 : m_os( &os )
330 , m_is_color_output(is_color_output)
331 {
332 os << setcolor(is_color_output, attr, fg, bg, &m_state);
333 }
334
335 ~scope_setcolor()
336 {
337 if (m_os) {
338 *m_os << setcolor(m_is_color_output, &m_state);
339 }
340 }
341private:
342 scope_setcolor(const scope_setcolor& r);
343 scope_setcolor& operator=(const scope_setcolor& r);
344 // Data members
345 std::ostream* m_os;
346 setcolor::state m_state;
347 bool m_is_color_output;
348};
349
350
351#define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color ) \
352 utils::scope_setcolor const sc(is_color_output, os, utils::attr, utils::color); \
353 boost::ignore_unused( sc ) \
354/**/
355
356} // namespace utils
357} // namespace unit_test
358} // namespace boost
359
360#include <boost/test/detail/enable_warnings.hpp>
361
362#endif // BOOST_TEST_UTILS_SETCOLOR_HPP
363

source code of include/boost/test/utils/setcolor.hpp