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