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 
23 // STL
24 #include <iostream>
25 #include <cstdio>
26 
27 #include <boost/test/detail/suppress_warnings.hpp>
28 
29 #ifdef _WIN32
30   #include <windows.h>
31 
32   #if defined(__MINGW32__) && !defined(COMMON_LVB_UNDERSCORE)
33     // mingw badly mimicking windows.h
34     #define COMMON_LVB_UNDERSCORE 0x8000
35   #endif
36 #endif
37 
38 //____________________________________________________________________________//
39 
40 namespace boost {
41 namespace unit_test {
42 namespace utils {
43 
44 // ************************************************************************** //
45 // **************                    term_attr                 ************** //
46 // ************************************************************************** //
47 
48 struct term_attr { enum _ {
49     NORMAL    = 0,
50     BRIGHT    = 1,
51     DIM       = 2,
52     UNDERLINE = 4,
53     BLINK     = 5,
54     REVERSE   = 7,
55     CROSSOUT  = 9
56 }; };
57 
58 // ************************************************************************** //
59 // **************                   term_color                 ************** //
60 // ************************************************************************** //
61 
62 struct term_color { enum _ {
63     BLACK    = 0,
64     RED      = 1,
65     GREEN    = 2,
66     YELLOW   = 3,
67     BLUE     = 4,
68     MAGENTA  = 5,
69     CYAN     = 6,
70     WHITE    = 7,
71     ORIGINAL = 9
72 }; };
73 
74 // ************************************************************************** //
75 // **************                    setcolor                  ************** //
76 // ************************************************************************** //
77 
78 #ifndef _WIN32
79 class setcolor {
80 public:
81     // Constructor
setcolor(bool is_color_output=false,term_attr::_ attr=term_attr::NORMAL,term_color::_ fg=term_color::ORIGINAL,term_color::_ bg=term_color::ORIGINAL)82     explicit    setcolor( bool is_color_output = false,
83                           term_attr::_  attr = term_attr::NORMAL,
84                           term_color::_ fg   = term_color::ORIGINAL,
85                           term_color::_ bg   = term_color::ORIGINAL )
86     : m_is_color_output(is_color_output)
87     {
88         m_command_size = std::sprintf( m_control_command, "%c[%c;3%c;4%cm",
89           0x1B,
90           static_cast<char>(attr + '0'),
91           static_cast<char>(fg + '0'),
92           static_cast<char>(bg + '0'));
93     }
94 
95     friend std::ostream&
operator <<(std::ostream & os,setcolor const & sc)96     operator<<( std::ostream& os, setcolor const& sc )
97     {
98        if (sc.m_is_color_output && (&os == &std::cout || &os == &std::cerr)) {
99           return os.write( sc.m_control_command, sc.m_command_size );
100        }
101        return os;
102     }
103 
104 private:
105     // Data members
106     bool        m_is_color_output;
107     char        m_control_command[13];
108     int         m_command_size;
109 };
110 
111 #else
112 
113 class setcolor {
114 
115 protected:
set_console_color(std::ostream & os,WORD * attributes=NULL) const116   void set_console_color(std::ostream& os, WORD *attributes = NULL) const {
117     if (!m_is_color_output) {
118       return;
119     }
120     DWORD console_type;
121     if (&os == &std::cout) {
122       console_type = STD_OUTPUT_HANDLE;
123     }
124     else if (&os == &std::cerr) {
125       console_type =  STD_ERROR_HANDLE;
126     }
127     else {
128       return;
129     }
130     HANDLE hConsole = GetStdHandle(console_type);
131 
132     if(hConsole == INVALID_HANDLE_VALUE || hConsole == NULL )
133       return;
134 
135     if(attributes != NULL) {
136       SetConsoleTextAttribute(hConsole, *attributes);
137       return;
138     }
139 
140     CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
141     GetConsoleScreenBufferInfo(hConsole, &consoleInfo);
142     saved_attributes = consoleInfo.wAttributes;
143 
144     WORD fg_attr = 0;
145     switch(m_fg)
146     {
147     case term_color::WHITE:
148       fg_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
149       break;
150     case term_color::BLACK:
151       fg_attr = 0;
152       break;
153     case term_color::RED:
154       fg_attr = FOREGROUND_RED;
155       break;
156     case term_color::GREEN:
157       fg_attr = FOREGROUND_GREEN;
158       break;
159     case term_color::CYAN:
160       fg_attr = FOREGROUND_GREEN | FOREGROUND_BLUE;
161       break;
162     case term_color::MAGENTA:
163       fg_attr = FOREGROUND_RED | FOREGROUND_BLUE;
164       break;
165     case term_color::BLUE:
166       fg_attr = FOREGROUND_BLUE;
167       break;
168     case term_color::YELLOW:
169       fg_attr = FOREGROUND_RED | FOREGROUND_GREEN;
170       break;
171     case term_color::ORIGINAL:
172     default:
173       fg_attr = saved_attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
174       break;
175     }
176 
177     WORD bg_attr = 0;
178     switch(m_bg)
179     {
180     case term_color::BLACK:
181       bg_attr = 0;
182       break;
183     case term_color::WHITE:
184       bg_attr = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
185       break;
186     case term_color::RED:
187       bg_attr = BACKGROUND_RED;
188       break;
189     case term_color::GREEN:
190       bg_attr = BACKGROUND_GREEN;
191       break;
192     case term_color::BLUE:
193       bg_attr = BACKGROUND_BLUE;
194       break;
195     case term_color::ORIGINAL:
196     default:
197       bg_attr = saved_attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
198       break;
199     }
200 
201     WORD text_attr = 0;
202     switch(m_attr)
203     {
204     case term_attr::BRIGHT:
205       text_attr = FOREGROUND_INTENSITY;
206       break;
207     case term_attr::UNDERLINE:
208       text_attr = COMMON_LVB_UNDERSCORE;
209       break;
210     default:
211       break;
212     }
213 
214     SetConsoleTextAttribute(hConsole, fg_attr | bg_attr | text_attr);
215     return;
216   }
217 
218 public:
219   // Constructor
setcolor(bool is_color_output=false,term_attr::_ attr=term_attr::NORMAL,term_color::_ fg=term_color::ORIGINAL,term_color::_ bg=term_color::ORIGINAL)220   explicit    setcolor(
221     bool is_color_output = false,
222     term_attr::_  attr = term_attr::NORMAL,
223     term_color::_ fg   = term_color::ORIGINAL,
224     term_color::_ bg   = term_color::ORIGINAL )
225   : m_is_color_output(is_color_output)
226   , m_attr(attr)
227   , m_fg(fg)
228   , m_bg(bg)
229   {}
230 
231   friend std::ostream&
operator <<(std::ostream & os,setcolor const & sc)232     operator<<( std::ostream& os, setcolor const& sc )
233   {
234     sc.set_console_color(os);
235     return os;
236   }
237 
238 private:
239   bool m_is_color_output;
240   term_attr::_ m_attr;
241   term_color::_ m_fg;
242   term_color::_ m_bg;
243 
244 protected:
245   // Data members
246   mutable WORD saved_attributes;
247 };
248 
249 #endif
250 // ************************************************************************** //
251 // **************                 scope_setcolor               ************** //
252 // ************************************************************************** //
253 
254 #ifndef _WIN32
255 
256 struct scope_setcolor {
scope_setcolorboost::unit_test::utils::scope_setcolor257     scope_setcolor() : m_os( 0 ) {}
scope_setcolorboost::unit_test::utils::scope_setcolor258     explicit    scope_setcolor( bool is_color_output,
259                                 std::ostream& os,
260                                 term_attr::_  attr = term_attr::NORMAL,
261                                 term_color::_ fg   = term_color::ORIGINAL,
262                                 term_color::_ bg   = term_color::ORIGINAL )
263     : m_os( &os )
264     , m_is_color_output( is_color_output )
265     {
266         os << setcolor( is_color_output, attr, fg, bg );
267     }
~scope_setcolorboost::unit_test::utils::scope_setcolor268     ~scope_setcolor()
269     {
270         if( m_os )
271             *m_os << setcolor( m_is_color_output );
272     }
273 private:
274     scope_setcolor(const scope_setcolor& r);
275     scope_setcolor& operator=(const scope_setcolor& r);
276     // Data members
277     std::ostream* m_os;
278     bool m_is_color_output;
279 };
280 
281 #else
282 
283 struct scope_setcolor : setcolor {
scope_setcolorboost::unit_test::utils::scope_setcolor284   scope_setcolor() : m_os( 0 ) {}
scope_setcolorboost::unit_test::utils::scope_setcolor285   explicit    scope_setcolor(
286     bool is_color_output,
287     std::ostream& os,
288     term_attr::_  attr = term_attr::NORMAL,
289     term_color::_ fg   = term_color::ORIGINAL,
290     term_color::_ bg   = term_color::ORIGINAL )
291   : setcolor(is_color_output, attr, fg, bg)
292   , m_os( &os )
293   {
294     os << *this;
295   }
296 
~scope_setcolorboost::unit_test::utils::scope_setcolor297   ~scope_setcolor()
298   {
299     if (m_os) {
300       set_console_color(*m_os, &this->saved_attributes);
301     }
302   }
303 private:
304   scope_setcolor(const scope_setcolor& r);
305   scope_setcolor& operator=(const scope_setcolor& r);
306   // Data members
307   std::ostream* m_os;
308 };
309 
310 
311 #endif
312 
313 #define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color )               \
314     utils::scope_setcolor const sc(is_color_output, os, utils::attr, utils::color); \
315     boost::ignore_unused( sc )                                                      \
316 /**/
317 
318 } // namespace utils
319 } // namespace unit_test
320 } // namespace boost
321 
322 #include <boost/test/detail/enable_warnings.hpp>
323 
324 #endif // BOOST_TEST_UTILS_SETCOLOR_HPP
325